跨域問題及其解決方法(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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...