關(guān)于跨域

前段時間學(xué)習(xí)了AJAX墩新,已經(jīng)可以從后臺拿到JSON串】咦可是出現(xiàn)了問題海渊,目前我發(fā)送的請求都是在同域下的請求,如果我想拿到其它域的數(shù)據(jù)哲鸳,便會受到瀏覽器的同源策略限制臣疑,于是便學(xué)習(xí)的跨域的相關(guān)知識,這篇文章便是用于對這些知識進行復(fù)習(xí)徙菠。

一讯沈、關(guān)于瀏覽器的同源策略和跨域

  • 什么是同源婿奔?
    同源就是相同的域名缺狠,端口和協(xié)議,這三個相同的話就視為同一個域萍摊,本域下的JS腳本只能讀寫本域下的數(shù)據(jù)資源挤茄,無法訪問其它域的資源,例如:
    同協(xié)議:都是http或者都是https冰木;
    同域名:都是oxc.com穷劈;
    同端口:都是8080或者3000笼恰;

  • 什么是同源策略?
    同源策略是瀏覽器為了用戶的個人信息以及企業(yè)數(shù)據(jù)的安全而設(shè)置的一種策略歇终,不同源的客戶端腳本是不能在對方未允許的情況下訪問或索取對方的資源社证;

此圖為瀏覽器因為同源策略報錯
  • 同源策略的重要性
    前面所說,同源策略是瀏覽器為了安全起見而設(shè)定练湿,那么如果沒有同源策略會發(fā)生什么事呢?
    情景一:泄露信息审轮,我登陸了淘寶肥哎,然后又登陸了一個惡意網(wǎng)站,惡意網(wǎng)站發(fā)送AJAX請求獲取淘寶的信息接口疾渣,而這個時候我已經(jīng)登陸過淘寶篡诽,所以瀏覽器附帶了我個人的淘寶cookie,一起發(fā)送給惡意網(wǎng)站榴捡;
    情景二:盜取數(shù)據(jù)杈女,某網(wǎng)站花重金購買一部電影的播放權(quán),我找到該網(wǎng)站接口后吊圾,直接把這部電影拿到手达椰,然后搞到自己的網(wǎng)站上去播放;
    由此可見项乒,為了安全起見的同源策略是必不可少了啰劲,但同時也給ajax請求帶來了很大的麻煩,比如大型網(wǎng)站不可能把整個網(wǎng)站的所有資源都放在同一個服務(wù)器上檀何,這時候跨域就成了必不可少的技能蝇裤;

  • 什么是跨域?
    跨域就是解決同源策略帶來的不便频鉴,通過JS去獲取不同源之間的數(shù)據(jù)資源或者進行信息的傳遞栓辜。


跨域的幾種實現(xiàn)方法

一、 jsonp

  • 什么是jsonp垛孔?

JSONP(JSON with Padding)是JSON的一種“使用模式”藕甩,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。

  • jsonp的原理和使用步驟

jsonp其實就是利用script標簽本身可跨域周荐,并且可以將其src屬性里的資源下載下來的設(shè)定從而達成目的辛萍。
具體使用步驟如下:
本域部分:
1.首先動態(tài)創(chuàng)建script標簽;
2.創(chuàng)建回調(diào)函數(shù)callback(假定函數(shù)名為aaa)羡藐,然后將該函數(shù)與callback字段結(jié)合成鍵值對的形式贩毕,例如:callback=aaa,接著將其與遠端(不同源)的接口url結(jié)合成如下形式:
http.....................php?callback=aaa
3.將創(chuàng)建的script標簽的src引向結(jié)合后的接口http.....................php?callback=aaa即可仆嗦;
跨域服務(wù)器部分:
1.獲取到回調(diào)函數(shù)aaa后辉阶,把需要發(fā)送的數(shù)據(jù)與函數(shù)aaa進行包裝,使用字符串拼接的方式組成如下形式再發(fā)回給本域:
aaa({"name": "xiaoming", "age": "1000"});
這時候數(shù)據(jù)就已經(jīng)到手了
最后:
瀏覽器會調(diào)用函數(shù)aaa,把獲得的數(shù)據(jù)以參數(shù)形式傳遞進去谆甜,進行數(shù)據(jù)處理垃僚;
PS:由上述步驟可見,jsonp的使用是需要遠端支持的规辱。

  • jsonp的缺陷

1.因為src屬性自己獲取數(shù)據(jù)要在url后面加上數(shù)據(jù)參數(shù)谆棺,那么這個方式就只有g(shù)et,所以jsonp也只能用get方式獲取數(shù)據(jù)罕袋;
2.jsonp只能解決跨域獲取資源問題改淑,但是不能解決不同域頁面之間的JS調(diào)用問題;
3.安全性問題:如果提供jsonp的遠端存在注入漏洞浴讯,它返回的數(shù)據(jù)就有可能是被人操控的朵夏。那么調(diào)用過這個遠端接口的所有網(wǎng)頁就都有可能被操控;
4.jsonp調(diào)用失敗不會返回失敗的http狀態(tài)碼榆纽,有可能會是200OK仰猖;

  • 小實例

一個運用了jsonp制作出來的半成品音樂播放器


二、CORS

  • 什么是CROS奈籽?

CROS全稱Cross-Origin Resource Sharing(跨域資源共享)饥侵,它是一個W3C標準,支持使用AJAX向跨域服務(wù)器發(fā)出AJAX請求衣屏;

  • CORS的兼容性

截圖自caniuse網(wǎng)

CORS兼容性

  • CORS的原理

個人類比:同源策略好比一個黑名單爆捞,這個黑名單非常嚴格,把所有的不同源客戶端腳本都進行了限制訪問勾拉,而CORS則是一個白名單煮甥,可以將允許訪問的客戶端腳本添加進這個白名單中,使其能進行訪問藕赞;

  • 實現(xiàn)方式

CORS通信的實現(xiàn)只能依賴跨域服務(wù)器的支持成肘,而在本域下的的代碼只是普通的AJAX請求;
通過在跨域服務(wù)器中對回應(yīng)頭進行設(shè)置斧蜕,實現(xiàn)對指定的域進行數(shù)據(jù)交互双霍,如下代碼是對回應(yīng)頭進行的設(shè)置
header("Access-Control-Allow-Origin", "a.oxc.com")
這個代碼實現(xiàn)了a.oxc.com這個域名對其數(shù)據(jù)的訪問;

  • 步驟

1.本域:發(fā)出普通的AJAX請求
2.跨域服務(wù)器:添加回應(yīng)頭信息:header('Access-Control-Allow-Origin', '允許跨域進行訪問的域名')
PS:這個回應(yīng)頭信息中Access-Control-Allow-Origin是允許跨域訪問批销,而后面的域名是允許進行跨域訪問的域名洒闸,如果第二個參數(shù)是一個星號*,就是無限制均芽,所有的域都可以對其進行跨域訪問丘逸;
3.本域分兩種情況:
已經(jīng)被允許跨域訪問:
在回應(yīng)頭處出現(xiàn)一個鍵值對,如:Access-Control-Allow-Origin: http://a.com:8080掀宋;
未允許進行跨域訪問:
①:可能是跨域服務(wù)器不支持CORS跨域訪問深纲,那么就不會有類似:Access-Control-Allow-Origin: http://a.com:8080的回應(yīng)頭信息仲锄;
②:跨域服務(wù)器不支持本域進行訪問,也會有回應(yīng)頭信息湃鹊,該信息標注那些域是可以進行訪問的儒喊,比如:跨域服務(wù)器支持a.com進行訪問,而我用b.com對其進行訪問币呵,回應(yīng)頭就會回復(fù):Access-Control-Allow-Origin: http://a.com:8080字段怀愧,表明只有a.com是支持訪問的;
出現(xiàn)如下錯誤:

  • 實際使用小例子

需求:用a.oxc.com獲取接口為b.oxc.com的服務(wù)器上發(fā)回的信息

1.修改hosts文件:

修改hosts文件

2.寫一個按鈕余赢,點擊獲取數(shù)據(jù)芯义,接口號為:'http://b.oxc.com:8080/hello'

  <button id="btn">點擊</button>
  <script>
    var btn = document.querySelector('#btn');
    btn.addEventListener('click', function(){
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status === 200){
            console.log(xhr.responseText)
          }
        }
      }
      xhr.open('get', 'http://b.oxc.com:8080/hello', true)
      xhr.send();
    })

3.跨域服務(wù)器設(shè)置回應(yīng)頭,只允許a.oxc.com對其進行訪問:
header('Access-Control-Allow-Origin', 'http://a.oxc.com:8080')

4.效果圖:

打印回應(yīng)信息
回應(yīng)頭
用其他域名對其進行訪問的回應(yīng)頭信息
  • 其它的回應(yīng)頭設(shè)置

此外没佑,我們還可以對回應(yīng)頭的一些信息進行設(shè)置:
1.Access-Control-Allow-Credentials
該信息指定是否發(fā)送cookie毕贼,可以設(shè)置true或者false温赔,true是允許蛤奢,false為不允許;
2.Access-Control-Expose-Headers
因為XMLHttpRequest對象中的getResponseHeader()方法只能接受6個基本的回應(yīng)頭信息:Cache-Control陶贼、Content-Language啤贩、Content-Type、Expires拜秧、Last-Modified痹屹、Pragma,如果需要拿到更多的回應(yīng)頭信息就要對Access-Control-Expose-Headers進行設(shè)置枉氮,例如:
Access-Control-Expose-Headers: aaa就能拿到回應(yīng)頭信息中的aaa字段志衍;

  • CORS與jsonp的對比
    • jsonp比CORS優(yōu)秀的地方
      1.jsonp兼容性較好,而CORS在IE中只兼容IE10以上瀏覽器聊替,此外在IE7或以下的IE瀏覽器中楼肪,因為沒有XMLHttpRequest對象,只支持ActiveX對象惹悄,所以注定無法使用CORS春叫,而jsonp這時候就可以大放異彩;
    • CORS比jsonp優(yōu)秀的地方
      1.CORS在前端部分只需要發(fā)送普通的AJAX請求即可泣港,使用起來和不跨域時并無不同暂殖,更加的方便;
      2.因為第一條当纱,所以CORS支持其它的請求方式(比如post呛每、put等);
    • 選型
      在有選擇的情況下坡氯,兼容老瀏覽器可以使用jsonp莉给,主流瀏覽器可以選用CORS毙石;

三、降域

  • 什么是降域颓遏?

降域就是當(dāng)兩個一級域名相同但二級域名不同時(如:a.oxc.com和b.oxc.com中主域名都是oxc.com)徐矩,對兩個域名都設(shè)置document.domain = 主域名來達到跨域的目的;

  • 降域的限制性

使用降域來達成跨域的目的有非常大的限制性:
1.主域名要相同:a.com和b.com就不行叁幢,a.oxc.com和b.oxc.com就可以滤灯;
2.降域只適用于iframe窗口和獲取cookie,但不能獲取LocalStorage 和 IndexDB ;

  • 降域小例子

需求:當(dāng)在a.oxc.com的輸入框中輸入字符曼玩,b.oxc.com的輸入框中也會出現(xiàn)相同字符

1.寫下a頁面(a.oxc.com)和b(b.oxc.com)頁面鳞骤,其中b頁面通過a頁面的iframe標簽嵌入了a頁面
a頁面:

<body>
<div>
    <input type="text" id="ipt" placeholder="a.oxc">
</div>
<iframe src="http://b.oxc.com:8080/b.html" frameborder="0" scrolling="no"></iframe>
    <script>
        // 獲取輸入框
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
        // 獲取b的輸入框輸入的字段,讓a的輸入框字段相等
         window.frames[0].ipt.value = this.value
         console.log(this.value);
       })


    </script>
</body>

b頁面:

<body>
<div>
    <input type="text" id="ipt" placeholder="b.oxc">
</div>

    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
        // 讓a的輸入框的字段與b的輸入框的字段相等
         window.parent.frames.ipt.value = this.value;
       })
       

    </script>
</body>

2.為a和b頁面分別添加document.domain = oxc.com

3.效果圖:


降域小例子效果圖

4.a頁面的cookie黍判,b頁面也可以進行讀取



四豫尽、postMessage

  • 什么是postMessage?

1.postMessage是window對象下的一個方法顷帖,他使得不同主域名之間也可以進行跨域通信:例如:使用a.com向b.com進行通信美旧;
2.postMessage方法接收兩個參數(shù),第一個參數(shù)是需要發(fā)送的消息贬墩,第二個參數(shù)接收發(fā)送的域名榴嗅,如:
window.postMessage('abc', 'a.com')

  • postMessage使用小例子一

需求:當(dāng)在a.com的輸入框中輸入字符,b.com的輸入框中也會出現(xiàn)相同字符陶舞;
代碼如下:

a.com代碼:

<div>
    <input type="text" id="ipt" placeholder="a.oxc">
</div>
<iframe src="http://b.com:8080/b.html" frameborder="0" scrolling="no"></iframe>
    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
         window.frames[0].postMessage(this.value, 'http://b.com:8080')
         console.log(this.value);
       })

       // 監(jiān)聽message事件
       window.addEventListener('message', function(e){
          ipt.value = e.data;
       })

b.com代碼:

<div>
    <input type="text" id="ipt" placeholder="b.oxc">
</div>

    <script>
       var ipt = document.querySelector('#ipt');
       ipt.addEventListener('input', function(e) {
         window.parent.frames.postMessage(this.value, 'http://a.com:8080')
       })
       
       window.addEventListener('message', function(e){
          ipt.value = e.data;
       })
    </script>

效果圖:

  • postMessage使用小例子二
    1.a.com監(jiān)聽消息事件嗽测,并把接收到的消息放進輸入框中;
    2.在a.com中用window.open打開b.com肿孵,然后在b.com用window.opener.postMessage向a.com的輸入框發(fā)送消息

步驟圖:

第一步:a.com中打開b.com
第二步:在b.com中通過window.opener定位到a.com
第三部:調(diào)用b.com的window.opener.postMessage方法向a.com的輸入框發(fā)送消息
a.com接收到了消息
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唠粥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子停做,更是在濱河造成了極大的恐慌晤愧,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雅宾,死亡現(xiàn)場離奇詭異养涮,居然都是意外死亡,警方通過查閱死者的電腦和手機眉抬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門贯吓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜀变,你說我怎么就攤上這事悄谐。” “怎么了库北?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵爬舰,是天一觀的道長们陆。 經(jīng)常有香客問我,道長情屹,這世上最難降的妖魔是什么坪仇? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮垃你,結(jié)果婚禮上椅文,老公的妹妹穿的比我還像新娘。我一直安慰自己惜颇,他們只是感情好皆刺,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凌摄,像睡著了一般羡蛾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锨亏,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天痴怨,我揣著相機與錄音,去河邊找鬼屯伞。 笑死腿箩,一個胖子當(dāng)著我的面吹牛豪直,可吹牛的內(nèi)容都是我干的劣摇。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼弓乙,長吁一口氣:“原來是場噩夢啊……” “哼末融!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起暇韧,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤勾习,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后懈玻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巧婶,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年涂乌,在試婚紗的時候發(fā)現(xiàn)自己被綠了艺栈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡湾盒,死狀恐怖湿右,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情罚勾,我是刑警寧澤毅人,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布吭狡,位于F島的核電站,受9級特大地震影響丈莺,放射性物質(zhì)發(fā)生泄漏划煮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一缔俄、第九天 我趴在偏房一處隱蔽的房頂上張望般此。 院中可真熱鬧,春花似錦牵现、人聲如沸铐懊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽科乎。三九已至,卻和暖如春贼急,著一層夾襖步出監(jiān)牢的瞬間茅茂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工太抓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留空闲,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓走敌,卻偏偏與公主長得像碴倾,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子掉丽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容