詳解5種跨域方式及其原理

同源定義 
若是兩個頁面擁有相同的協議(protocol),端口(若是指定),和主機,那麼這兩個頁面就屬於同一個源(origin)。javascript

如下是同源檢測的示例php

URL 結果 緣由
http://store.company.com/dir2/other.html Success  
http://store.company.com/dir/inner/another.html Success  
https://store.company.com/secure.html Failure 協議不一樣
http://store.company.com:81/dir/etc.html Failure 端口不一樣
http://news.company.com/dir/other.html Failure 主機不一樣

1.jsonp

script標籤是不受同源策略影響的,它能夠引入來自任何地方的js文件。 
而jsonp的原理就是,在客戶端和服務端定義一個函數,當客戶端發起一個請求時,服務端返回一段javascript代碼,其中調用了在客戶端定義的函數,並將相應的數據做爲參數傳入該函數。html

 

function jsonp_cb(data) {java

   console.log(data);ajax

}chrome

function ajax(){json

   var url = "http://xx.com/test.php?jsonp_callback=jsonp_cb";跨域

   var script = document.createElement('script');瀏覽器

   // 發送請求服務器

   script.src = url;

   document.head.appendChild(script);

}

ajax()

服務端獲取到jsonp_callback傳遞的函數名jsonp_cb,返回一段對該函數調用的js代碼

 

jsonp_cb({

  "name": "story"

});

2.img ping

img標籤也是沒有跨域限制的,但它只能用來發送GET請求,且沒法獲取服務端的響應文本,能夠利用它實現一些簡單的、單向的跨域通訊,例如跟蹤用戶的點擊

 

var img = new Image();

img.onload = function(){

   console.log('done')

   img.onload = null;

   img = null;

}

img.src = "http://xx/xx.gif"

3.window.name

window對象擁有name屬性,它有一個特色:相同協議下,在一個頁面中,不隨URL的改變而改變 
示例代碼

 

window.name = 'string' // 字符串,通常容許的最大值爲2M

console.log(window.name)

location = 'http://funteas.com/'

此時,在控制檯輸入window.name,結果依然是」string」

 

window.name // "string"

window.name的值只能是字符串,任何其餘類型的值都會「轉化」爲字符串 
例如

 

window.name = function(){}

console.log(window.name)

// "function(){}"

經過window.name實現跨域也很簡單,iframe擁有contentWindow屬性,其指向該iframe的window對象的引用,若是在iframe的src指向的頁面中設置window.name值,那麼就能夠經過iframe.contentWindow.name就能夠拿到這個值了

 

var url = "http://funteas.com/lab/windowName";

var iframe = document.createElement('iframe')

iframe.onload = function(){

   var data = iframe.contentWindow.name

   console.log(data)

}

iframe.src = url

document.body.appendChild(iframe)

然而,chrome會提示你跨域了! 
而咱們已經知道window.name不隨URL的改變而改版,也就是說,onload時,已經獲取到了name,只不過由於不一樣源,當前頁面的腳本沒法拿到iframe.contentWindow.name,此時只須要把iframe.src改成同源便可

 

var url = "http://funteas.com/lab/windowName";

var iframe = document.createElement('iframe')

iframe.onload = function(){

   iframe.src = 'favicon.ico';

   var data = iframe.contentWindow.name

   console.log(data)

}

iframe.src = url

document.body.appendChild(iframe)

刷新頁面,你會發現iframe不斷刷新,這是由於每次onload,iframe的src被修改,而後再次觸發onload,從而致使iframe循環刷新,修改下便可

 

var url = "http://funteas.com/lab/windowName";

var iframe = document.createElement('iframe')

var state = true;

iframe.onload = function(){

   if(state === true){

       iframe.src = 'favicon.ico';

       state = false;

   }else if(state === false){

       state = null

       var data = iframe.contentWindow.name

       console.log(data)

   }

}

iframe.src = url

document.body.appendChild(iframe)

上面請求的是一個靜態頁面,而服務端一般須要的是動態數據

 

echo '<script> window.name = "{\"name\":\"story\"}"</script>';

4.postMessage

postMessage容許不一樣源之間的腳本進行通訊,用法

 

otherWindow.postMessage(message, targetOrigin);

  • otherWindow 引用窗口 iframe.contentwindow 或 window.open返回的對象

  • message 爲要傳遞的數據

  • targetOrigin 爲目標源

 

// http://127.0.0.1:80

var iframe = document.createElement('iframe')

iframe.onload = function(){

   var popup = iframe.contentWindow

   popup.postMessage("hello", "http://127.0.0.1:5000");

}

iframe.src = 'http://127.0.0.1:5000/lab/postMessage'

document.body.appendChild(iframe)

// 監聽返回的postMessage

window.addEventListener("message", function(event){

   if (event.origin !== "http://127.0.0.1:5000") return;

   console.log(event.data)

}, false)

// http://127.0.0.1:5000/lab/postMessage

window.addEventListener("message", function(event){

   // 驗證消息來源

   if (event.origin !== "http://127.0.0.1") return;

   console.log(event.source); // 消息源 popup

   console.log(event.origin); // 消息源URI https://secure.example.net

   console.log(event.data); // 來自消息源的數據 hello

   // 返回數據

   var message = 'world';

   event.source.postMessage(message, event.origin);

}, false);

5.CORS

CORS(跨域資源共享)是一種跨域訪問的機制,可讓AJAX實現跨域訪問。它容許一個域上的腳本向另外一個域提交跨域 AJAX 請求。實現此功能很是簡單,只需由服務器發送一個響應標頭便可。

 

Access-Control-Allow-Origin: * // 容許來自任何域的請求

Access-Control-Allow-Origin: http://funteas.com/ // 僅容許來自http://funteas.com/的請求

當客戶端的ajax請求的url爲其餘域時,對於支持CORS的瀏覽器,請求頭會自動添加Origin,值爲當前host

 

var xhr = new XMLHttpRequest();

var url = 'http://bar.other/resources/public-data/';

xhr.open('GET', url, true);

xhr.send();

CORS默認不發送cookie,若是要發送cookie,須要設置withCredentials

 

var xhr = new XMLHttpRequest();

xhr.withCredentials = true;

同時,服務端也要設置

 

Access-Control-Allow-Credentials: true

查看MDN關於CORS的介紹【https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS】

以上是我使用過的跨域方式,其餘方式諸如document.domain、flash等,由於沒有用過,就再也不多做介紹,有興趣的同窗能夠本身瞭解下。

相關文章
相關標籤/搜索