跨域解決方案

跨域解決方案

跨域解決方案有:設(shè)置document.domain,使用帶src標(biāo)簽,JSONP,navigation對象,CORS,window.postMessage,片段標(biāo)識符,window.name,WebSocket

設(shè)置document.domain

  • 原理:相同主域名不同子域名下的頁面,可以設(shè)置document.domain讓它們同域
  • 限制:同域document提供的是頁面間的互操作,需要載入iframe頁面
// URL http://a.com/foo
var ifr = document.createElement('iframe');
ifr.src = 'http://b.a.com/bar'; 
ifr.onload = function(){
    var ifrdoc = ifr.contentDocument || ifr.contentWindow.document;
    ifrdoc.getElementsById("foo").innerHTML);
};

ifr.style.display = 'none';
document.body.appendChild(ifr);

需要設(shè)置iframe的domain,將 document.domain往上設(shè)置一級,這樣即可操作DOM和Cookie

document.domain = 'a.com'

使用帶src標(biāo)簽

  • 原理:所有具有src屬性的HTML標(biāo)簽都是可以跨域的,包括<img>, <script>,<iframe>
  • 限制:只能用于GET方法

JSONP

利用script標(biāo)簽可以跨域這點(diǎn),跨域獲得的腳本包含一個(gè)客戶端和服務(wù)器端約定好的回調(diào)函數(shù),以及服務(wù)器端發(fā)送的數(shù)據(jù)。

jQuery實(shí)現(xiàn)

//URL具有callback參數(shù)時(shí), jQuery將會把它解釋為一個(gè)JSONP請求,創(chuàng)建一個(gè)<script>標(biāo)簽來完成該請求。
$.getJSON( "http://b.a.com/bar?callback=callback", function( data ){
    // 處理跨域請求得到的數(shù)據(jù)
});

JS實(shí)現(xiàn)

function loadJsonp(url,callback){
    var script = document.createElement('script'),
    rand = Math.random().toString().substring(2, 8),
    functionName = "getJsonStr" + rand;

    script.src = url + "?callback=" + functionName;

    window[functionName] = function(data) {
        if (callback) {
            callback(data);
        }
        try {
            delete window[functionName];
        } catch (e) {
            window[functionName] = undefined;
        }
    };

    var head = document.getElementsByTagName('head')[0];
    script.onload = function() {
        script.onload = undefined;
        head.removeChild(script);
    };
    script.onerror = function(e) {
        console.error(e);
    };

    head.appendChild(script);
}

跨域資源共享(CORS)

  • 原理:服務(wù)器設(shè)置Access-Control-Allow-OriginHTTP響應(yīng)頭之后,瀏覽器將會允許跨域請求,H5推薦的跨域方式。
  • 限制:瀏覽器需要支持HTML5,可以支持POST,PUT等方法

跨域發(fā)送Cookie

將xhr的屬性withCredentials設(shè)置為true后,即可攜帶目標(biāo)域的Cookie

// 原生
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.withCredentials = true;
xhr.send();
// jQ
$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

還需要服務(wù)器端設(shè)置Access-Control-Allow-Credentials響應(yīng)頭為true,并且將Access-Control-Allow-Origin設(shè)置為請求對應(yīng)的域名

既然Access-Control-Allow-Origin只允許單一域名, 服務(wù)器可能需要維護(hù)一個(gè)接受 Cookie 的 Origin 列表, 驗(yàn)證 Origin 請求頭字段后直接將其設(shè)置為Access-Control-Allow-Origin的值。 (這一實(shí)踐來自 Stackoverflow) 值得注意的是在 CORS 請求被重定向后 Origin 頭字段會被置為 null。 此時(shí)可以選擇從Referer頭字段計(jì)算得到Origin。

preflight

對于非簡單請求,CORS 機(jī)制跨域會首先進(jìn)行 preflight(一個(gè) OPTIONS 請求), 該請求成功后才會發(fā)送真正的請求。 這一設(shè)計(jì)旨在確保服務(wù)器對 CORS 標(biāo)準(zhǔn)知情,以保護(hù)不支持 CORS 的舊服務(wù)器。

preflight.png

window.postMessage

  • 原理:HTML5允許窗口之間發(fā)送消息
  • 限制:瀏覽器需要支持HTML5,獲取窗口句柄后才能相互通信

這是一個(gè)安全的跨域通信方法,postMessage(message,targetOrigin)也是HTML5引入的特性。 可以給任何一個(gè)window發(fā)送消息,不論是否同源。第二個(gè)參數(shù)可以是*但如果你設(shè)置了一個(gè)URL但不相符,那么該事件不會被分發(fā)。

// 頁面A,URL: http://a.com/foo
var win = window.open('http://b.com/bar');
win.postMessage('Hello, bar!', 'http://b.com'); 
// 頁面B,URL: http://b.com/bar
window.addEventListener('message',function(event) {
    console.log(event.data);
});

片段標(biāo)識符

  • 原理:改變網(wǎng)頁#后面的部分,被改變的網(wǎng)頁可以通過監(jiān)聽onhashchange事件得到通知
  • 限制:URL具有長度的限制,只能傳送字符串
// A窗口
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
// B窗口
window.onhashchange = function(){
    var message = window.location.hash;
}

window.name

  • 原理:只要在同一個(gè)窗口里,前一個(gè)網(wǎng)頁設(shè)置了這個(gè)屬性,后一個(gè)網(wǎng)頁可以讀取它。
  • 限制:必須監(jiān)聽子窗口window.name屬性的變化,影響網(wǎng)頁性能。

WebSocket

  • 原理:WebSocket使用ws、wss作為通信協(xié)議,改協(xié)議沒有同源策略
  • 限制:需要瀏覽器支持

參考文獻(xiàn)

JS高程(第三版)
Web開發(fā)中跨域的幾種解決方案
瀏覽器同源策略及其規(guī)避方法
CORS 跨域發(fā)送 Cookie
CORS 跨域中的 preflight 請求

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是跨域? 2.) 資源嵌入:、、、等dom標(biāo)簽,還有樣式中background:url()、@font-fac...
    電影里的夢i閱讀 2,471評論 0 5
  • 作者:安靜de沉淀https://segmentfault.com/a/1190000011145364 什么是跨...
    layjoy閱讀 1,381評論 1 8
  • 題目1: 什么是同源策略 同源策略限制了從一個(gè)源加載的文檔或腳本如何與來自另一個(gè)源的資源進(jìn)行交互。這是一個(gè)用于隔離...
    饅頭Mum閱讀 1,683評論 0 1
  • 記得臨走前的前幾天,我仿佛還這就是平平常常的時(shí)候,和過去的每一個(gè)悠閑的大學(xué)時(shí)光一樣,只不過平常很一般的同學(xué)關(guān)系突...
    Yachilles閱讀 342評論 0 0
  • 當(dāng)年鏖戰(zhàn)欲何求?蕩寇除倭報(bào)國讎。 喋血惠通破困局,橫刀同古斬?cái)城酢?為匡族運(yùn)扶危卵,忍把殘軀拋野丘。 苦雨凄風(fēng)弔烈...
    widoms閱讀 414評論 0 0

友情鏈接更多精彩內(nèi)容