跨域問題及其解決方法(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
  • 分組和樹形結構是不一樣的。 樹形結構是以遞歸形式存在。分組是以鍵值對存在的形式,類似於GroupBy這樣的形式。 舉個例子 ID NAME SEX Class 1 張三 男 1 2 李四 女 2 3 王二 男 1 當以Sex為分組依據時則是 Key Value 男 1 張三 男 1 3 王二 男 1 ...
  • NetCore中將SQLServer資料庫備份為Sql腳本 描述: 最近寫項目收到了一個需求, 就是將SQL Server資料庫備份為Sql腳本, 如果是My Sql之類的還好說, 但是在網上搜了一大堆, 全是教你怎麼操作SSMS的, 就很d疼! 解決方案: 通過各種查找資料, 還有一些老哥的幫助, ...
  • 我的Notion Clowd.Squirrel Squirrel.Windows 是一組工具和適用於.Net的庫,用於管理 Desktop Windows 應用程式的安裝和更新。 Squirrel.Windows 對 Windows 應用程式的實現語言沒有任何要求,甚至無需服務端即可完成增量更新。 ...
  • 轉載請註明來源 https://www.cnblogs.com/brucejiao/p/16188865.html 謝謝! 轉載請註明來源 https://www.cnblogs.com/brucejiao/p/16188865.html 謝謝! 轉載請註明來源 https://www.cnblog ...
  • 1. Netty源碼研究筆記(3)——Channel系列 依舊是通過先縱向再橫向的研究方法,在開篇中,我們發現不管是Sever還是Client,最終的啟動是通過調用channel的對應方法來完成的,而這個動作實際在channel綁定的eventLoop中執行。 接下來,我們繼續EchoSever、E ...
  • 大家好,今天給大家介紹一款輕量、快速、穩定可編排的組件式規則引擎框架LiteFlow。 一、LiteFlow的介紹 LiteFlow官方網站和代碼倉庫地址 官方網站:https://yomahub.com/liteflow Gitee托管倉庫:https://gitee.com/dromara/li ...
  • 我使用Spring AOP實現了用戶操作日誌功能 今天答辯完了,復盤了一下系統,發現還是有一些東西值得拿出來和大家分享一下。 需求分析 系統需要對用戶的操作進行記錄,方便未來溯源 首先想到的就是在每個方法中,去實現記錄的邏輯,但是這樣做肯定是不現實的,首先工作量大,其次違背了軟體工程設計原則(開閉原 ...
  • 《零基礎學Java》 繪製幾何圖形 Java可以分別使用 Graphics 和 Graphics2D 繪製圖形,Graphics類 使用不同的方法繪製不同的圖形(drawLine()方法可f以繪製線、drawRect()方法用於繪製矩形、drawOval()方法用於繪製橢圓形)。 Graphics類 ...
  • 本期教程人臉識別第三方平臺為虹軟科技,本文章講解的是人臉識別RGB活體追蹤技術,免費的功能很多可以自行搭配,希望在你看完本章課程有所收穫。 ...
  • 很多人都喜歡使用黑色的主題樣式,包括我自己,使用了差不多三年的黑色主題,但是個人覺得在進行視窗轉換的時候很廢眼睛。 比如IDEA是全黑的,然後需要看PDF或者WORD又變成白色的了,這樣來回切換導致眼睛很累,畢竟現在網頁以及大部分軟體的界面都是白色的。那麼還是老老實實的使用原來比較順眼的模式吧。 1 ...