跨域問題及其解決方法(JSONP&CORS)

来源:https://www.cnblogs.com/wangguoxinyue/archive/2022/05/09/16248211.html
-Advertisement-
Play Games

一、什麼是跨域 當a.qq.com功能變數名稱下的頁⾯或腳本試圖去請求b.qq.com功能變數名稱下的資源時,就是典型的跨域行為。跨域的定義從受限範圍可以分為兩種,⼴義跨域和狹義跨域。 (一)廣義跨域 ⼴義跨域通常包含以下三種⾏為:1. 資源跳轉:a鏈接、重定向。2. 資源嵌⼊:<link>、<script>、<i ...


一、什麼是跨域

當a.qq.com功能變數名稱下的頁⾯或腳本試圖去請求b.qq.com功能變數名稱下的資源時,就是典型的跨域行為。跨域的定義從受限範圍可以分為兩種,⼴義跨域和狹義跨域。

 

 

(一)廣義跨域

⼴義跨域通常包含以下三種⾏為:
1. 資源跳轉:a鏈接、重定向。
2. 資源嵌⼊:<link>、<script>、<img>、<frame>等dom標簽,還有樣式中background:url()、@font-face()等⽂件外鏈。
3. 腳本請求:瀏覽器存儲數據讀取、dom和js對象的跨域操作、js發起的ajax請求等。
其中,資源跳轉和資源嵌⼊⾏為可以正常請求到跨域資源,腳本請求在未經任何處理的情況下,通常會有跨域

(二)狹義跨域

狹義跨域正是瀏覽器同源策略限制的⼀類請求場景,即我們通常說的跨域⾏為,通常包含以下三種⾏為:
1. cookie、localStorage和indexDB⽆法讀取。
2. dom和js對象⽆法獲取和操作。
3. ajax請求⽆法發送


二、常見的跨域場景 

  瀏覽器安全的基石就是“同源策略”,即如果A網站設置的cookie,B網站如果想訪問必須滿足三個要求:同一種協議、同一個功能變數名稱、同一個埠號。
  舉例來說,http://www.example.com/dir/page.html這個網址,協議是http://,功能變數名稱是www.example.com,埠號是80(可以省略,http預設80,https預設443)
  例如:

  http://www.example.com/dir2/other.html :同源

  http://example.com/dir/other.html :不同源(功能變數名稱不同)  

  http://v2.www.example.com/dir/other.html :不同源(功能變數名稱不同

  http://www.example.com:81/dir/other.html :不同源(埠不同)

 

三、跨域解決方法

(一)ajax跨域請求解決方案

  1.jsonp跨域解決

jsonp (JSON with Padding),是JSON的⼀種“使⽤模式”,可以讓⽹頁跨域讀取數據。其本質是利⽤script標簽的開放策略,瀏覽器傳遞callback參數到後端,後端返回數據時會將callback參數作為函數名來包裹數據,從⽽瀏覽器就可以跨域請求數據並定製函數來⾃動處理返回數據。

  代碼示例:
var script = document.createElement('script');
script.type = 'text/javascript';
// 傳參callback給後端,後端返回時執⾏這個在前端定義的回調函數
script.src = 'http://a.qq.com/index.php?callback=handleCallback';
document.head.appendChild(script);
// 回調執⾏函數
function handleCallback(res) {
alert(JSON.stringify(res));
}

 

 
  • jsonp跨域優點:

jsonp相容性強,適⽤於所有瀏覽器,尤其是IE10及以下瀏覽器。

  • jsonp跨域缺點:

沒有關於調⽤錯誤的處理。
只⽀持GET請求,不⽀持POST請求以及⼤數據量的請求,⽽且也⽆法拿到相關的返回頭,狀態碼等數據。
callback參數惡意註⼊,可能會造成xss漏洞。


  2.跨域資源共用(CORS) 

跨域資源共用(Cross-origin resource sharing,CORS)是⼀個 W3C標準,允許瀏覽器向跨域伺服器發送請求,從⽽剋服了ajax只能同源使⽤的限制。CORS需要瀏覽器和伺服器同時⽀持。⽬前,所有主流瀏覽器(IE10及以上)使⽤XMLHttpRequest對象都可⽀持該功能,IE8和IE9需要使⽤XDomainRequest對象進⾏相容。

CORS整個通信過程都是瀏覽器⾃動完成,瀏覽器⼀旦發現ajax請求跨源,就會⾃動在頭信息中增加Origin欄位,⽤來說明本次請求來⾃哪個源(協議+功能變數名稱+端⼝)。因此,實現CORS通信的關鍵是伺服器,需要伺服器配置Access-Control-Allow-Origin頭信息。當CORS請求需要攜帶cookie時,需要服務端配置Access-Control-Allow-Credentials頭信息,前端也需要設置withCredentials。瀏覽器將CORS請求分成兩類:簡單請求和⾮簡單請求。簡單請求需要滿⾜以下兩⼤條件:

1. 請求⽅法是以下三種⽅法之⼀:HEAD、GET、POST。
2. HTTP的頭信息不超出以下⼏種欄位:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type:只限
於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain。
CORS簡單請求跨域實現流程:

 



// IE8/9需⽤XDomainRequest相容
var xhr = new XMLHttpRequest(); 
// 前端設置是否帶cookie
xhr.withCredentials = true;
xhr.open('post', 'http://a.qq.com/index.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=saramliu');
xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

 

  • CORS跨域優點:

⽀持所有類型的HTTP請求,功能完善。
通過onerror事件監聽進⾏調⽤錯誤處理;
通過Access-Control-Allow-Origin進⾏資源訪問授權。

  • CORS跨域缺點:

⽬前主流瀏覽器(IE10及以上)都⽀持CORS,但IE8和IE9需要使⽤XDomainRequest對象進⾏相容,IE7及以下瀏覽器不⽀持

  3.伺服器代理

伺服器代理,顧名思義即在發送跨域請求時,後端進⾏代理中轉請求⾄伺服器端,然後將獲取的數據返回給前端。⼀般適⽤於以下場景:

針對IE7及以下瀏覽器摒棄Flash插件的情況,配置代理接⼝與前端頁⾯同源,並中轉⽬標伺服器接⼝,則ajax請求不存在跨域問題。外⽹前端頁⾯⽆法訪問內⽹接⼝,配置代理接⼝允許前端頁⾯訪問,並中轉內⽹接⼝,則外⽹前端頁⾯可以跨域訪問內⽹接⼝。

伺服器代理實現流程:

 

  • 伺服器代理優點:

在不使⽤Flash的情況下,相容不⽀持CORS的瀏覽器跨域請求。

  • 伺服器代理缺點:

後端需要⼀定的改造⼯作量。

(⼆)前端跨域通信解決⽅案

前端跨域通信是指瀏覽器中兩個不符合同源策略的前端頁⾯進⾏通信。

  1.document.domain+iframe

 

 

document.domain+iframe⽅案代碼⽰例:

<!-- A頁⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq.com/b.html"></iframe>
<script>
document.domain = "qq.com";
var windowB = document.getElementById("iframe").contentWindow;
alert("B頁⾯的user變數:" + windowB.user);
</script>

<!-- B頁⾯ http://b.qq.com/b.html --> <script> document.domain = "qq.com"; var user = "saramliu"; </script>

 

 

  • document.domain+iframe⽅案優點:

實現邏輯簡單,⽆需額外中轉頁⾯

  • document.domain+iframe⽅案缺點:

僅適⽤於主域相同,⼦域不同的前端通信跨域場景


  2.location.hash+iframe

當兩個不符合同源策略且主域不同的頁⾯需要進⾏跨域通信時,可以利⽤url的hash值改變但不刷新頁⾯的特性,實現簡單的前端跨域通信。

 

 

<!-- A頁⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
    // 監聽c.html傳來的hash值
    window.onhashchange = function () {
        alert("B頁⾯傳遞數據:" + location.hash.substring(1));
    };
</script>
<!-- B頁⾯ http://b.qq1.com/b.html -->
<iframe id="iframe" src="http://a.qq.com/c.html"></iframe>
<script>
    // 向c.html傳遞hash值
    var iframe = document.getElementById('iframe');
    setTimeout(function() {
        iframe.src = iframe.src + '#user=saramliu';
    }, 1000);
</script>
<!-- C頁⾯ http://a.qq.com/c.html -->
<script>
    // 監聽b.html傳來的hash值
    window.onhashchange = function () {
        // 操作同域a.html的hash值,傳遞數據
        window.parent.parent.location.hash = window.location.hash.substring(1);
    };
</script>
  • location.hash+iframe⽅案優點

可以解決主域不同的前端通信跨域問題。
hash改變,頁⾯不會刷新。

  • location.hash+iframe⽅案缺點:

受部分瀏覽器安全機制限制,需要額外的同源中轉頁⾯,且中轉頁⾯需要js邏輯來修改hash值。
通信數據類型及長度均受限,且數據外顯在url上,存在⼀定安全風險。

  3.window.name+iframe

window.name屬性的獨特之處在於,name值在不同頁⾯(甚⾄不同功能變數名稱)載入後依舊存在,並且可以⽀持⾮常長的name值(2MB)。

window.name+iframe代碼⽰例:

<!-- A頁⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
var state = 0;
var iframe = document.getElementById('iframe');
iframe.onload = function() {
if (state === 1) {
// 第2次onload成功後,讀取同域window.name中數據
alert(iframe.contentWindow.name);
} else if (state === 0) {
// 第1次onload成功後
state = 1;
}
};
</script>

<!-- B頁⾯ http://b.qq1.com/b.html --> <script> window.name = "這⾥是B頁⾯!"; window.location = "http://a.qq.com/c.html"; </script>

 

  • window.name+iframe⽅案優點:

可以解決主域不同的前端通信跨域問題。
通信數據類型不受限,且長度可達2MB。

  • window.name+iframe⽅案缺點:

需要額外的同源中轉頁⾯,但中轉頁可以為空⽩頁。

  4.postMessage

postMessage是HTML5 XMLHttpRequest Level2中的API,且是為數不多可以跨域操作的window屬性之⼀,它通常⽤於解決以下⽅⾯的問題:

1. 頁⾯和其打開的新窗⼝的數據傳遞。
2. 多窗⼝之間消息傳遞。
3. 頁⾯與嵌套iframe消息傳遞。

postMessage是⼀種安全的跨域通信⽅法。當a.html獲得對b.html的window對象後,a.html調⽤postMessage⽅法分發⼀個MessageEvent消息。b.html通過監聽message事件即可獲取a.html傳遞的數據,從⽽實現跨域通信。

  • postMessage⽅法的語法如下:
otherWindow.postMessage(message、targetOrigin、[transfer])

 

otherWindow:⽬標窗⼝的window對象,⽐如iframe的contentWindow屬性、執⾏window.open返回的window對象等。

message:將要發送給其他window的數據。

targetOrigin:指定哪些窗⼝能接收到消息事件,其值可以是字元串*(表⽰⽆限制)或者是“協議+主機+端⼝號”。

transfer(可選):是⼀串和message同時傳遞的Transferable對象,這些對象的所有權將被轉移給消息的接收⽅,⽽發送⼀⽅將不再保有所有權。

postMessage⽅案代碼⽰例:

<!-- A頁⾯ http://a.qq.com/a.html -->
<iframe id="iframe" src="http://b.qq1.com/b.html"></iframe>
<script>
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {meesage: "這⾥是A頁⾯發的消息"}; 
        var url = "http://b.qq1.com/b.html";
        // 向B頁⾯發送消息
        iframe.contentWindow.postMessage(JSON.stringify(data), url);
    };
    window.addEventListener("message", function(e) {
        alert("B頁⾯發來消息:" + JSON.parse(e.data));
    });
</script>

<!-- B頁⾯ http://b.qq1.com/b.html --> <script> window.addEventListener("message", function(e) { alert("A頁⾯發來消息:" + JSON.parse(e.data)); var data = {meesage: "這⾥是B頁⾯發的消息"}; var url = "http://a.qq.com/a.html"; window.parent.postMessage(JSON.stringify(data), url); }, false); </script>

 

  • postMessage⽅案優點:

可以解決多種類型的前端跨域通信問題;

  • postMessage⽅案缺點:

相容性⽅⾯相對差⼀點,IE8及以下瀏覽器不⽀持該⽅法,IE9只⽀持postMessage傳遞string類型的數據,⽽標準的postMessage消
息數據可以是任何類型。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 OpenHarmony 生態發展過程中,涌現了大批優秀的代碼貢獻者,本專題旨在表彰貢獻、分享經驗,文中內容來自嘉賓訪談,不代表 OpenHarmony 工作委員會觀點。 ...
  • 如今,身材管理已成為人們日常生活中重點關註的內容,除了運動之外,熱量的攝入也是重中之重,想要維持理想的身體健康和體重狀態,人們需要長期測量自己每日攝入食物的體量、熱量和營養價值,這需要實踐者有極強的耐心、執行力和知識儲備,從而成為了一部分身材管理道路上的攔路虎。 因此很多運動健康類App中支持食物識 ...
  • 今天內容挺多,因為想的是必須在一天內把這個vuex完成,說實話這裡面要記得東西還是蠻多的,主要是分為原生的和簡便方法兩種都是vue官方定義的,只不過看你要用哪種,vuex感覺要是用熟練了不得了,直接可以把vue起飛了,數據到處用,那種起飛的感覺,曾經體驗過,所以這個應該還是可以多練練的。 明天進入v ...
  • 8 個你應該立即停止使用的無效 HTML 元素 HTML 規範的開發是一個漸進的過程,有時會出現問題。隨著時間的推移,許多元素和屬性被添加到 HTML 中,直到後來 Web 社區集體意識到有更好的方法時才被刪除。由於已棄用和過時的元素和屬性已經存在於網路上,因此許多現代瀏覽器繼續支持它們的使用。儘管 ...
  • 前言 在我們日常代碼開發過程中,組件的使用是必不可少的,我們也會去封裝組件。但是大家寫組件的風格各式各樣,沒有一個統一的準則。而且也沒有遵循軟體開發的原則:高內聚、低耦合;因為我是給行業提供代碼的,行業給交付提供代碼。我們要儘量去減少大家的接入成本,降低接入成本的最好方案就是我們在設計組件的時候編寫 ...
  • HBuilderx快速新建VUE項目 一、安裝HBuilderx開發工具 官網:HBuilderX HBuilderXH是HTML的第一個字母,Builder是builder,X是HBuilder的下一個版本。我們也被稱為HX。 HBuilderX是輕量級但功能強大的 IDE。 它的官網上介紹到HB ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、面向對象 一般使用字面量的形式直接創建對象,但是這種創建方式對於創建大量相似對象的時候,會產生大量的重覆代碼。但 js和一般的面向對象的語言不同,在 ES6 之前它沒有類的概念。但是可以使用函數來進行模擬,從而產生出可復用的對象創建方 ...
  • DNS 解析:將功能變數名稱解析成 IP 地址 TCP 連接:TCP 三次握手 發送 HTTP 請求 伺服器處理請求並返回 HTTP 報文 瀏覽器解析渲染頁面 斷開連接:TCP 四次揮手 一、什麼是URL? URL(Uniform Resource Locator),統一資源定位符,用於定位互聯網上資源,俗 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...