【鄭州-第132期】前端跨域問題有哪些常用的解決方式?

大家好,我是IT修真院鄭州分院第一期的學(xué)員胡嘉杰,一枚正直純潔善良的WEB前端程序員。

今天給大家分享一下,修真院官網(wǎng)JS任務(wù)5,深度思考中的知識(shí)點(diǎn)——前端跨域問題有哪些常用的解決方式?

1.背景介紹

為什么需要跨域?

受瀏覽器同源策略的限制,本域的js不能操作其他域的頁面對(duì)象(比如DOM)。 但在安全限制的同時(shí)也給注入iframe或是ajax應(yīng)用上帶來了不少麻煩。 所以我們要通過一些方法使本域的js能夠操作其他域的頁面對(duì)象或者使其他域的 js能操作本域的頁面對(duì)象(iframe之間)。

這里需要明確的一點(diǎn)是: 所謂的域跟js的存放服務(wù)器沒有關(guān)系, 比如baidu.com的頁面加載了google.com的js, 那么此js的所在域是baidu.com而不是google.com。也就是說, 此時(shí)該js能操作baidu.com的頁面對(duì)象,而不能操作google.com的頁面對(duì)象。

2.知識(shí)剖析

1.跨域:指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。 它是由瀏覽器的同源策略造成的, 是瀏覽器對(duì)javascript施加的安全限制。

2.同源策略:它是由Netscape提出的一個(gè)著名的安全策略。 同源是指,域名,協(xié)議,端口相同。瀏覽器執(zhí)行javascript腳本時(shí), 會(huì)檢查這個(gè)腳本屬于那個(gè)頁面,如果不是同源頁面,就不會(huì)被執(zhí)行。

3.為什么script標(biāo)簽引入的文件不受同源策略的限制?: 因?yàn)閟cript標(biāo)簽引入的文件內(nèi)容是不能夠被客戶端的js獲取到的, 不會(huì)影響到被引用文件的安全,所以沒必要使script標(biāo)簽引入的文件遵循瀏覽器的同源策略。 而通過ajax加載的文件內(nèi)容是能夠被客戶端js獲取到的,所以ajax必須遵循同源策略, 否則被引入文件的內(nèi)容會(huì)泄漏或者存在其他風(fēng)險(xiǎn)。

3.常見問題

有哪些常用的跨域方式?

4.解決方案

4.1使用iFrame訪問另一個(gè)域。 然后再從另一個(gè)頁面讀取iFrame的內(nèi)容。jquery等有一些封裝。據(jù)說Firefox等可能不支持讀取另一個(gè)iFrame的內(nèi)容。

a)document.domain + iframe (domain 屬性可返回下載當(dāng)前文檔的服務(wù)器域名,只有在主域相同的時(shí)候才能使用該方法)

b)location.hash + iframe(原理是利用location.hash來進(jìn)行傳值):假設(shè)域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html傳遞信息。

1) cs1.html首先創(chuàng)建自動(dòng)創(chuàng)建一個(gè)隱藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html頁面

2) cs2.html響應(yīng)請(qǐng)求后再將通過修改cs1.html的hash值來傳遞數(shù)據(jù)

3) 同時(shí)在cs1.html上加一個(gè)定時(shí)器,隔一段時(shí)間來判斷l(xiāng)ocation.hash的值有沒有變化,一旦有變化則獲取獲取hash值

注:由于兩個(gè)頁面不在同一個(gè)域下IE、Chrome不允許修改parent.location.hash的值,所以要借助于a.com域名下的一個(gè)代理iframe

c)window.name + iframe(window.name 的好處在于:name 值在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長(zhǎng)的 name 值【2MB】)

4.2CORS(背后的思想,就是使用自定義的HTTP頭部讓瀏覽器與服務(wù)器進(jìn)行溝通, 從而決定請(qǐng)求或響應(yīng)是應(yīng)該成功,還是應(yīng)該失敗。)

4.3跨域 XMLHttpRequest 請(qǐng)求。

4.4通過JSONP跨域: 通過script標(biāo)簽引入一個(gè)js或者是一個(gè)其他后綴形式(如PHP,jsp等) 的文件,此文件返回一個(gè)js函數(shù)的調(diào)用,如返回JSONP_getUsers(["paco","john","lili"]), 也就是說此文件返回的結(jié)果調(diào)用了JSONP_getUsers函數(shù),并且把["paco","john","lili"]傳進(jìn)去, 這個(gè)["paco","john","lili"]是一個(gè)用戶列表。那么如果此時(shí)我們的頁面中有一個(gè)JSONP_getUsers函數(shù), 那么JSONP_getUsers就被調(diào)用到,并且傳入了用戶列表。此時(shí)就實(shí)現(xiàn)了在本域獲取其他域數(shù)據(jù)的功能, 也就是跨域。

4.5 動(dòng)態(tài)創(chuàng)建script: 這種方法其實(shí)是JSONP跨域的簡(jiǎn)化版,JSONP只是在此基礎(chǔ)上加入了回調(diào)函數(shù)。

4.6服務(wù)器代理。

5.編碼實(shí)戰(zhàn)

5.1使用iFrame跨域

a)document.domain + iframe :

//在www.a.com/a.html中:

document.domain = 'a.com';

var ifr = document.createElement('iframe');

ifr.src = 'http://www.script.a.com/b.html';

ifr.display = none;

document.body.appendChild(ifr);

ifr.onload = function(){

var doc = ifr.contentDocument ||ifr.contentWindow.document;

//在這里操作doc,也就是b.html

ifr.onload = null;

};

//在www.script.a.com/b.html中:

document.domain = 'a.com';

b)location.hash + iframe:

//b.html頁面的關(guān)鍵代碼如下:

try {

parent.location.hash = 'data';

} catch (e) {

// ie、chrome的安全機(jī)制無法修改parent.location.hash,

var ifrproxy = document.createElement('iframe');

ifrproxy.style.display = 'none';

ifrproxy.src = "http://www.baidu.com/proxy.html#data";

document.body.appendChild(ifrproxy);

}

//proxy.html頁面的關(guān)鍵代碼如下:

//因?yàn)閜arent.parent(即baidu.com/a.html)

和baidu.com/proxy.html屬于同一個(gè)域,

所以可以改變其location.hash的值

parent.parent.location.hash = self.location.hash.substring(1);

c)window.name + iframe:

//1) 創(chuàng)建a.com/cs1.html

//2) 創(chuàng)建a.com/proxy.html,并加入如下代碼

function proxy(url, func) {

var isFirst = true;

ifr = document.createElement('iframe');

loadFunc = function () {

if (isFirst) {

ifr.contentWindow.location = 'http://a.com/cs1.html';

isFirst = false;

} else {

func(ifr.contentWindow.name);

ifr.contentWindow.close();

document.body.removeChild(ifr);

ifr.src = '';

ifr = null;

}

};

ifr.src = url;

ifr.style.display = 'none';

if (ifr.attachEvent) ifr.attachEvent('onload', loadFunc);

else ifr.onload = loadFunc;

document.body.appendChild(iframe);

}

proxy('http://www.baidu.com/', function (data) {

console.log(data);

});

//3) 在b.com/cs1.html中包含:

window.name = '要傳送的內(nèi)容';

5.3跨域 XMLHttpRequest 請(qǐng)求:

var xhr = new XMLHttpRequest();//建立xhr對(duì)象

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {//等待回調(diào)

alert(xhr.statusText);

} else {

alert("Request was unsuccessful: " + xhr.status);

}

xhr.open("get", "example.php", false);

//請(qǐng)求的類型、請(qǐng)求的URL和是否異步發(fā)送

xhr.send(data);//參數(shù)

}

5.4通過JSONP跨域:

function handleResponse(response){

console.log('The responsed data is: '+response.data);

}

var script = document.createElement('script');

script.src = 'http://www.baidu.com/json/?callback=handleResponse';

document.body.insertBefore(script, document.body.firstChild);

/*handleResonse({"data": "zhe"})*/

//原理如下:

//當(dāng)我們通過script標(biāo)簽請(qǐng)求時(shí)

//后臺(tái)就會(huì)根據(jù)相應(yīng)的參數(shù)(json,handleResponse)

//來生成相應(yīng)的json數(shù)據(jù)(handleResponse({"data": "zhe"}))

//最后這個(gè)返回的json數(shù)據(jù)(代碼)就會(huì)被放在當(dāng)前js文件中被執(zhí)行

//至此跨域通信完成

6.擴(kuò)展思考

怎么選擇跨域的方法?

跨域的方法很多,不同的應(yīng)用場(chǎng)景我們都可以找到一個(gè)最合適的解決方案。 比如單向的數(shù)據(jù)請(qǐng)求,我們應(yīng)該優(yōu)先選擇JSONP或者window.name, 雙向通信優(yōu)先采取location.hash, 在未與數(shù)據(jù)提供方達(dá)成通信協(xié)議的情況下我們也可以用server proxy的方式來抓取數(shù)據(jù)。

7.參考文獻(xiàn)

參考一: 前端解決跨域問題的8種方案(最新最全)

參考二:解決前端跨域請(qǐng)求的幾種方式

參考三:深入理解前端跨域方法和原理

8.更多討論

怎么用NGINX跨域?


前端跨域問題有哪些常用的解決方式?_騰訊視頻

------------------------------------------------------------------------------------------------------------------------

技能樹.IT修真院

“我們相信人人都可以成為一個(gè)工程師,現(xiàn)在開始,找個(gè)師兄,帶你入門,掌控自己學(xué)習(xí)的節(jié)奏,學(xué)習(xí)的路上不再迷?!?。

這里是技能樹.IT修真院,成千上萬的師兄在這里找到了自己的學(xué)習(xí)路線,學(xué)習(xí)透明化,成長(zhǎng)可見化,師兄1對(duì)1免費(fèi)指導(dǎo)。快來與我一起學(xué)習(xí)吧~

我的邀請(qǐng)碼:64290793,或者你可以直接點(diǎn)擊此鏈接:http://www.jnshu.com/login/1/64290793

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

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

  • 什么是跨域? 2.) 資源嵌入:、、、等dom標(biāo)簽,還有樣式中background:url()、@font-fac...
    電影里的夢(mèng)i閱讀 2,473評(píng)論 0 5
  • 1. 什么是跨域? 跨域一詞從字面意思看,就是跨域名嘛,但實(shí)際上跨域的范圍絕對(duì)不止那么狹隘。具體概念如下:只要協(xié)議...
    他在發(fā)呆閱讀 861評(píng)論 0 0
  • 1. 什么是跨域? 跨域一詞從字面意思看,就是跨域名嘛,但實(shí)際上跨域的范圍絕對(duì)不止那么狹隘。具體概念如下:只要協(xié)議...
    w_zhuan閱讀 622評(píng)論 0 0
  • 一:同源策略 1.what's this 所謂同源是指,域名,協(xié)議,端口相同。當(dāng)瀏覽器運(yùn)行一個(gè)JS腳本時(shí)會(huì)進(jìn)行同源...
    吃茶葉蛋閱讀 417評(píng)論 1 0
  • 我的孩子總是抱怨無聊,想讓我放下所有的事情去跟他玩理解你的孩子,你自己和情形在我們生活的這個(gè)社會(huì)里,孩子們習(xí)慣了別...
    但雨澤閱讀 526評(píng)論 0 0

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