1. 程式人生 > >跨域解決方案合集

跨域解決方案合集

瀏覽器的同源策略會導致跨域,這裡同源策略又分為以下兩種
1. DOM同源策略:禁止對不同源頁面DOM進行操作。這裡主要場景是iframe跨域的情況,不同域名的iframe是限制互相訪問的。
2. XmlHttpRequest同源策略:禁止使用XHR物件向不同源的伺服器地址發起HTTP請求。
只要協議、域名、埠有任何一個不同,都被當作是不同的域,之間的請求就是跨域操作。

解決方式:

針對DOM不同源:
1. document.domain
2. Location.hash
3. postMessage

針對XmlHttpRequest不同源:
1. 跨域資源共享 CORS
*

http://www.ruanyifeng.com/blog/2016/04/cors.html
* 實現CORS通訊的關鍵是伺服器,只要伺服器實現了CORS介面,就可以實現跨源通訊
* CORS請求分為:簡單請求 & 非簡單請求
* 伺服器相應中CORS相關欄位都帶 Access-Control- 開頭
* 客戶端中 withCredentials 屬性
2. jsonp
* 只支援GET請求,支援老式瀏覽器,可以向不支援CORS的網路請求資料
3. 伺服器代理

Jsonp:

JSONP是一種非正式傳輸協議,該協議的一個要點就是允許使用者傳遞一個callback引數給服務端,然後服務端返回資料時會將這個callback引數作為函式名來包裹住JSON資料,這樣客戶端就可以隨意定製自己的函式來自動處理返回資料了。JSONP只能是get請求,script也是一種get請求,利用script標籤沒有跨域限制的特性來達到與第三方通訊的目的,第三方產生的響應為json資料的包裝(jsonp,json padding),即後端輸出的response text必須符合js語法

//方式1
//這種方式無法對請求進行錯誤處理
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

//方式2
$.ajax({
    url: 'https://api.douban.com/v2/book/search?callback=handleResponse',
    data: {
        q: 'javascript',
        count: 1
    },
    jsonp: 'callback',//傳遞給請求處理程式或頁面的,用以獲得jsonp回撥函式名的引數名(一般預設為:callback)
    dataType: 'jsonp',//自定義的jsonp回撥函式名稱,預設為jQuery自動生成的隨機函式名,也可以不寫,jQuery會把資料拿出來放到success函式的引數裡
    jsonpCallback: 'handleResponse',
    success (data){
        console.log(data);
    },
    error (XMLHttpRequest, textStatus, errorThrown){
        console.error(XMLHttpRequest, textStatus, errorThrown)
    }
});

//方式3(僅介面是.json字尾才可以跨域,即訪問遠端json檔案)
$.getJSON("GetUserbyName.aspx?name=ww&callback=?",
    function(date){
        //....
    }
)
  1. html標籤的src屬性沒有同源限制(支援跨域),瀏覽器解析script標籤時,會自動下載src屬性值(url)指向的資源;
  2. script標籤指向的資原始檔被下載後,其中的內容會被立即執行;伺服器端的程式會解析src屬性值中的url傳遞的引數,根據這些引數針對性返回一個/多個函式呼叫表示式,這些函式呼叫表示式的引數就是客戶端跨域想得到的資料;
  3. 伺服器生成、返回的檔案中,表示式呼叫的函式是已經在本地提前定義好的,而引數就是希望從跨域伺服器拿到的資料。
  4. 字面的script標籤可以,動態新增到dom樹中的script也可以,後者更方便繫結事件。
  5. img link iframe 等元素都可以傳送跨域請求
  6. 只支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript呼叫的問題。

document.domain

用document.domain來指定域有侷限性,也就是一級域名一致才可以

www.sojson.com 下指到 sojson.com 是可以的。
icp.sojson.com 下指到 sojson.com 是可以的。

www.sojson.com 下指到 www.baidu.com 是不行的。
sojson.com 指到 baidu.com 還是不行的。

在需要通訊的兩個域中都寫下如下程式碼:

if(document.domain != 'sojson.com'){
    document.domain = 'sojson.com';
}

保證一致即可

一級域名  有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。

二級域名  是指增加了一級,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com  等等

document.domain 描述物件
document.domain 只能修改為一級域名一致的域名

document.domain

用document.domain來指定域有侷限性,也就是一級域名一致才可以

    www.sojson.com  下指到 sojson.com 是可以的。
    icp.sojson.com  下指到 sojson.com 是可以的。

    www.sojson.com  下指到 www.baidu.com  是不行的。
    sojson.com  指到 baidu.com  還是不行的。

在需要通訊的兩個域中都寫下如下程式碼:

if(document.domain != 'sojson.com'){
    document.domain = 'sojson.com';
}

保證一致即可

一級域名  有的人叫根域名,如:sojson.com、baidu.com、sina.com、sina.com.cn、sina.cn.net 等等。

二級域名  是指增加了一級,包括www。如:www.sojson.com、icp.sojson.com、zhidao.baidu.com、www.baidu.com  等等

location.hash

通過把資料寫在url的#號後面來傳遞資料。a.com 裡的頁面 a1.html巢狀 b.com 的 b1.html,b1.html 修改 parent.hash,a1.html 監聽 hashchange 來實現。(ie、chrome的安全機制無法修改parent.location.hash,所以要利用一箇中間的 a.com 域下的代理iframe,即在 b1.html 中增加一個 iframe,src為 a.com 域下的頁面)

利用hash跨域,資料直接暴露在了url中,資料容量和型別都有限

//a1.html
function startRequest(){  
    var ifr = document.createElement('iframe');  
    ifr.style.display = 'none';  
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';  
    document.body.appendChild(ifr);  
}  


function checkHash() {  
    try {  
        var data = location.hash ? location.hash.substring(1) : '';  
        if (console.log) {  
            console.log('Now the data is '+data);  
        }  
    } catch(e) {};  
}  
setInterval(checkHash, 2000);


//b1.html 模擬一個簡單的引數處理操作  
switch(location.hash){  
    case '#paramdo':  
        callBack();  
        break;  
    case '#paramset':  
        //do something……  
        break;  
}


function callBack(){  
    try {  
        parent.location.hash = 'somedata';  
    } catch (e) {  
        // ie、chrome的安全機制無法修改parent.location.hash,  
        // 所以要利用一箇中間的cnblogs域下的代理iframe  
        var ifrproxy = document.createElement('iframe');  
        ifrproxy.style.display = 'none';  
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意該檔案在"a.com"域下  
        document.body.appendChild(ifrproxy);  
    }  
}

//a2.html
//因為parent.parent和自身屬於同一個域,所以可以改變其location.hash的值  
parent.parent.location.hash = self.location.hash.substring(1);

postmessage