欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

跨域問題?同源策略大全

liguoquan
2024年12月27日 12:42 本文熱度 237
:跨域問題?同源策略大全


前言:跨域與同源策略

跨域:通常出現在Web開發中,特別是在涉及到Ajax請求或Fetch API調用時,當一個網頁嘗試從不同的源加載資源時,就會遇到跨域問題。這里所說的“不同的源”,是指請求資源的源(由協議、域名和端口號組成)與提供資源的源不一致。

http://  192.168.3.1  :3000  /home

協議(http),         域名(192.168.3.1),      端口(3000),   路徑(/home)

同源策略:是為了保護用戶的隱私和數據安全,如果沒有同源策略,惡意網站可以通過腳本非法獲取其他網站上的敏感數據,所以瀏覽器會通過實施同源策略來限制不同源之間的直接通信。同時,也有些特別的情況是不受同源策略限制的,比如:

img標簽下的

link標簽下的

script標簽下的

一:JSONP實現同源

  1. 借助script標簽的src屬性不受同源策略的影響來發送請求

  2. 給后端攜帶一個參數 callback 并在前端定義 callback 函數體

  3. 后端返回 callback 的調用形式并將要響應的值作為 callback 函數的參數

  4. 當瀏覽器接收到響應后,就會觸發全局的 callback 函數,從而讓 callback 以參數的形式接收后端的響應

前端代碼

js
代碼解讀
復制代碼
<script>    function jsonp(url, cb) {      return new Promise((resolve, reject) => {        const script = document.createElement('script');        // 注冊一個全局的回調函數        window[cb] = function(data) {          resolve(data);        };        // 設置腳本標簽的src屬性為請求的URL,并附加一個回調參數        script.src = `${url}?cb=${cb}`;        // 將腳本標簽添加到body中,觸發異步請求        document.body.appendChild(script);      });    }    // 使用jsonp函數發起請求    jsonp('http://localhost:3000', 'callback').then(res => {      console.log(res);  // 在控制臺輸出結果    }); </script>

后端代碼

js
代碼解讀
復制代碼
const http = require('http'); // 創建一個HTTP服務器實例,并指定一個處理請求的回調函數 http.createServer(function(req, res) {  // 解析請求的URL,并獲取查詢參數  const query = new URL(req.url, `http://${req.headers.host}`).searchParams;  // 檢查查詢參數中是否包含'cb'(callback)  if (query.get('cb')) {    // 獲取回調函數名    const cb = query.get('cb'); // 例如:'callback'    // 準備要返回的數據    const data = 'hello world';    // 構造JSONP格式的字符串,格式為:callback("hello world")    const result = `${cb}("${data}")`;    res.end(result);  } }).listen(3000);

$

但使用這種方法實現同源有兩個缺點:

  • 需要后端配合
  • 只支持 get 請求

二:cors實現同源

核心思想是后端通過Access-Control-Allow-Origin設置響應頭來指定允許的域名,以此來通知瀏覽器此時同源策略不生效

前端代碼

js
代碼解讀
復制代碼
   <script>        const xhr = new XMLHttpRequest();        xhr.open('GET', 'http://localhost:3000');        xhr.send();        xhr.onreadystatechange = function () {            if (xhr.readyState == 4 && xhr.status == 200) {                console.log(xhr.responseText);        }    }    </script>

后端代碼

js
代碼解讀
復制代碼
const http = require('http'); // 創建一個HTTP服務器實例,并指定一個處理請求的回調函數 http.createServer((req, res) => {   // 設置響應頭的狀態碼為200,表示成功   res.writeHead(200, {       // 設置Access-Control-Allow-Origin響應頭,允許來自'http://127.0.0.1:5500'的請求       'Access-Control-Allow-Origin': 'http://127.0.0.1:5500',   });   res.end('Hello World'); }).listen(3000);

同樣,也可以設置Access-Control-Allow-methods來設置相應的請求方法,post,get等等

三:proxy代理

  1. 前端應用將原本需要跨域訪問的請求發送給自身的后端服務器
  2. 后端服務器再將請求轉發至實際的目標服務器,并從目標服務器獲取數據
  3. 最后將數據返回給前端應用。

這樣通過后端服務器作為中間層代理轉發請求,可以繞過瀏覽器同源策略的限制,實現跨域數據的獲取。

實現過程:

  • 創建一個XMLHttpRequest對象并發送一個GET請求到后端(http://192.168.1.63:3000)。onreadystatechange事件處理器會在請求狀態改變時觸發,并在請求完成且響應狀態碼為200 OK時打印出響應文本。
js
代碼解讀
復制代碼
   <script>        const xhr = new XMLHttpRequest();        xhr.open('GET', 'http://192.168.1.63:3000');        xhr.send();        xhr.onreadystatechange = function () {            if (xhr.readyState == 4 && xhr.status == 200) {                console.log(xhr.responseText);        }    }    </script>
  • 后端創建一個簡單的HTTP服務器,監聽3000端口,設置響應頭Access-Control-Allow-Origin*,允許任何來源都可以訪問此資源,解決跨域問題。
  • 再創建一個新的HTTP請求到目標服務器192.168.1.63:3000,與前端設置的要一致,并將從目標服務器收到的數據轉發回原始請求者。
js
代碼解讀
復制代碼
const http = require('http'); http.createServer(function(req, res) {  // 設置響應頭允許任何來源訪問此資源  res.writeHead(200, {    "access-control-allow-origin": "*"  });  // 創建一個新的請求到目標服務器  const options = {    host: '192.168.1.63',    port: '3000',    path: '/',    method: 'GET',    headers: {}  };  // 發起代理請求  http.request(options, proxyRes => {    // 當從目標服務器接收到數據時,轉發給原始請求者    proxyRes.on('data', function(data) {      res.end(data.toString())    });  }).end(); // 結束代理請求 }).listen(3000); // 監聽3000端口

請注意,這樣的代理服務器僅適用于開發環境,在生產環境中應當謹慎使用,因為它可能帶來安全風險,如中間人攻擊等

四:nginx實現同源

相當于node代理,大致原理如下:

五:Websocket實現同源

  • websocket是http協議的一部分,所以它有同源策略
  • websocket是長連接,可以發送和接收消息
  • websocket是html5新增的協議,它是一種雙向通信協議,建立在tcp之上

實現過程: 前端

  • 創建一個新的 WebSocket 實例,并傳入 url 參數。
  • 設置 onopen 事件處理器,當 WebSocket 連接成功打開時,將 params 對象轉換為 JSON 字符串并通過 WebSocket 發送。
  • 設置 onmessage 事件處理器,當從 WebSocket 接收到消息時,解析接收到的數據,并調用 resolve 方法,將解析后的數據作為 Promise 的結果返回。
  • 調用 myWebSocket 函數,傳入 WebSocket 服務器的 URL  和一個包含對象并使用 .then 方法處理 Promise 的解決情況
js
代碼解讀
復制代碼
 <script>    function myWebSocket(url, params = {}) {      return new Promise(function(resolve, reject) {        //創建一個新的 `WebSocket` 實例        const socket = new WebSocket(url)                //將 `params` 對象轉換為 JSON 字符串并通過 WebSocket 發送。        socket.onopen = () => {          socket.send(JSON.stringify(params))        }                //解析接收到的數據,并作為 `Promise` 的結果返回        socket.onmessage = function(e) {          resolve(e.data);        }      })    }    myWebSocket('ws://localhost:3000', {age: 18}).then(res => {      console.log(res);      })  </script>

后端

  • npm init -y 初始化為后端項目
  • npm ws 安裝ws
  • 使用 ws 庫來創建一個 WebSocket 服務器,并監聽3000端口。
  • 監聽 'connection' 事件,每當有一個新的客戶端連接到 WebSocket 服務器時,就會觸發此事件處理器。
  • 為每個連接注冊一個 'message' 事件處理器,當從客戶端接收到消息時觸發。并設置一個定時器,每兩秒調用一次
js
代碼解讀
復制代碼
const WebSocket = require('ws'); // 創建一個 WebSocket 服務器實例,并監聽3000端口 const ws = new WebSocket.Server({ port: 3000 }); // 監聽 'connection' 事件,每當有新的客戶端連接到服務器時觸發 ws.on('connection', function(obj) {    // 監聽 'message' 事件,每當從客戶端接收到消息時觸發    obj.on('message', function(data) {        // 向客戶端發送一條歡迎消息        obj.send('歡迎訪問');        // 設置一個定時器,每隔2秒向客戶端發送一條消息        setInterval(() => {              obj.send();        }, 2000);    }); });

六:postMessage

當頁面一通過iframe嵌套了頁面二,這兩個頁面因為跨域無法進行通訊,可以使用postMessage實現跨域通訊

postMessage 是一種在不同窗口、文檔或框架之間安全地進行消息傳遞的方式,它支持跨源消息傳遞

下面帶友友們實操一下:

主頁 (index.html)

  • 初始化 obj 對象,包含姓名和年齡信息。
  • 當 <iframe> 加載完成后,通過 postMessage 發送 obj 對象給 detail.html。
  • index.html 的 onmessage 事件處理器接收到 detail.html 發送的回復消息。
js
代碼解讀
復制代碼
<body>    <h2>首頁</h2>    <iframe id="frame" src="http://127.0.0.1:5500/postMessage/detail.html" width="800" height="500" frameborder="0"></iframe>    <script>        // 定義一個對象,包含要傳遞的數據        let obj = {name: 'midsummer', age: 18};        // 當 iframe 加載完成后執行以下代碼        document.getElementById('frame').onload = function() {            // 向 iframe 中的頁面發送一個消息            this.contentWindow.postMessage(obj, 'http://127.0.0.1:8080');            // 設置全局的 onmessage 事件處理器,用于接收來自其他窗口的消息            window.onmessage = function(e) {                console.log(e.data); // 打印接收到的消息數據            };        };    </script> </body>

詳情頁 (detail.html)

  • 接收到來自 index.html 的消息。
  • 解析消息數據,并更新頁面上的顯示內容。
  • 向 index.html 發送回復消息。
js
代碼解讀
復制代碼
<body>    <h3>詳情頁 -- <span id="title"></span> </h3>    <script>        // 獲取頁面中的 span 元素,用于顯示信息        let title = document.getElementById('title');        // 設置全局的 onmessage 事件處理器,用于接收來自其他窗口的消息        window.onmessage = function (e) {            // 解構賦值,提取消息中的 data 屬性,以及消息來源的 origin 屬性            let { data: {name, age}, origin } = e;            // 更新 span 元素的文本內容,顯示發送過來的名字和年齡信息            title.innerText = `${name} ${age}`;            // 向消息來源(即發送消息的窗口)發送新的消息            e.source.postMessage(`midsummer現在${++age}歲`, origin);        };    </script> </body>

簡單來說就是通過設置 postMessage 的第二個參數為目標源地址,可以限制消息只能發送給指定源的窗口。當一個窗口接收到消息時,它可以通過 onmessage 事件處理器來處理消息,并且可以使用 e.source 來回發消息給發送方。

七:document.domain

當兩個頁面通過iframe進行嵌套,且兩個頁面的二級域名一致,可以使用document.domain實現同源 ,不知道二級域名的友友們可以參考下圖

主頁:

js
代碼解讀
復制代碼
<body>    <h2>首頁</h2>    <iframe id="frame" src="http://127.0.0.1:5500/postMessage/detail.html" width="800" height="500" frameborder="0"></iframe>    <script>        // 設置當前頁面的 document.domain 為 '127.0.0.1'        document.domain = '127.0.0.1';       // 當 iframe 加載完成時執行的函數        document.getElementById('frame').onload = function() {       // 輸出 contentWindow 中的 data 變量        console.log(this.contentWindow.data);      };    </script> </body>

詳情頁:

js
代碼解讀
復制代碼
<script> document.domain = '127.0.0.1' var data = 'domain' </script>

通過設置 document.domain放寬限制,允許在同一個頂級域名下的不同子域名之間進行通信。在 index.html 和 detail.html 中都設置了 document.domain 為 '127.0.0.1',確保 index.html 和 detail.html 之間的 document.domain 是相同的,從而繞過了同源策略的限制。


作者:midsummer18
鏈接:https://juejin.cn/post/7411168461500366860
來源:稀土掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

該文章在 2024/12/27 12:42:27 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved