前端跨域解決方案簡述

跨域是指一個(gè)域下的文檔或腳本試圖去請求另一個(gè)域下的資源染厅。比如:

  • 資源跳轉(zhuǎn): a鏈接、重定向津函、表單提交
  • 資源嵌入: <link>肖粮、<script>、<img>尔苦、<frame>等dom標(biāo)簽涩馆,還有樣式中background:url()、@font-face()等文件外鏈
  • 腳本請求: js發(fā)起的ajax請求允坚、dom和js對象的跨域操作等

我們通常所說的跨域主要是由于瀏覽器的 同源策略/SOP(Same origin policy) 限制的一類場景魂那。

1. 同源策略(Same origin policy)

1995年,同源政策由 Netscape 公司引入瀏覽器稠项。目前涯雅,所有瀏覽器都實(shí)行這個(gè)政策。同源政策的目的展运,是為了保證用戶信息的安全活逆,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
所謂同源是指三個(gè)相同:協(xié)議相同拗胜、域名相同蔗候、端口相同,有一個(gè)及以上不同即為非同源埂软。而非同源會限制以下三種行為:
1. Cookie锈遥、LocalStorage 和 IndexDB 無法讀取。
2. DOM 無法獲得勘畔。
3. AJAX 請求不能發(fā)送迷殿。

2. 解決方案

  1. JSONP
    在html頁面中通過相應(yīng)的標(biāo)簽從不同域名下加載靜態(tài)資源,是被瀏覽器允許的咖杂,JSONP便是基于此原理庆寺。通過動態(tài)創(chuàng)建<script>元素,再請求一個(gè)帶參網(wǎng)址實(shí)現(xiàn)跨域通信诉字,服務(wù)器收到請求后懦尝,會將數(shù)據(jù)放在回調(diào)函數(shù)的參數(shù)位置返回知纷。
function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://xxxx.com:7001/json?callback=xxx');  //callback指定回調(diào)函數(shù)名字
}
//回調(diào)執(zhí)行函數(shù)
function xxx(value) {
  console.log(value)
}

缺點(diǎn):只能發(fā)送get請求。

  1. CORS / 跨源資源分享(Cross-Origin Resource Sharing)
    CORS需要瀏覽器和服務(wù)器同時(shí)支持陵霉。目前琅轧,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10踊挠。
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText).msg)
  }
}
// xhr.withCredentials = true    //設(shè)置是否帶cookie
// 要發(fā)送Cookie乍桂,Access-Control-Allow-Origin就不能設(shè)為*,必須指定明確的效床、與請求網(wǎng)頁一致的域名
xhr.open('GET', 'http://xxxx.com:7001/cros')
xhr.send(null)

cors很大程度上是服務(wù)端進(jìn)行設(shè)置睹酌,返回響應(yīng),Response Headers會多出幾個(gè)以Access-Control-開頭的頭信息字段剩檀。具體可參考

  1. iframe + location.hash
    a.html(父頁面)
var iframe = document.createElement('iframe')
iframe.src = 'http://xxxx.com/hash.html'
document.body.appendChild(iframe);
window.onhashchange = function () {
  console.log(location.hash)    //通過監(jiān)聽hashchange事件得到通知
}

hash.html

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        var res = JSON.parse(xhr.responseText)
        parent.location.href = `http://yyyy.com/a.html#msg=${res.msg}` //改變父窗口的hash
    }
}
xhr.open('GET', 'http://xxxx.com/json', true)  //獲取數(shù)據(jù)
xhr.send(null)

  1. iframe + window.name
    瀏覽器窗口有window.name屬性憋沿。這個(gè)屬性的最大特點(diǎn)是,無論是否同源沪猴,只要在同一個(gè)窗口里辐啄,前一個(gè)網(wǎng)頁設(shè)置了這個(gè)屬性,后一個(gè)網(wǎng)頁可以讀取它运嗜。
    a.html(父頁面)
var iframe = document.createElement('iframe')
iframe.src = 'http://xxxx.com/name.html'
document.body.appendChild(iframe)

var times = 0
iframe.onload = function () {
    if (++times === 2) {
        console.log(JSON.parse(iframe.contentWindow.name))    //讀取子窗口的window.name
        //需要的話可以在獲取數(shù)據(jù)后銷毀這個(gè)iframe壶辜,釋放內(nèi)存;保證一定的安全性
        //function destoryFrame() {
          //iframe.contentWindow.document.write('');
          //iframe.contentWindow.close();
          //document.body.removeChild(iframe);
        //}
    }
}

name.html

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        window.name = xhr.responseText  //將數(shù)據(jù)賦給window.name
        location.     //跳至與父頁面相同域名下
    }
}
xhr.open('GET', 'http://xxxx.com/json', true)  //獲取數(shù)據(jù)
xhr.send(null)

window.name可以放置非常長的字符串(2MB)担租,但是需要監(jiān)聽子頁面window.name變化砸民,影響頁面性能。

  1. iframe + postMessage
    a.html(父頁面)
var iframe = document.createElement('iframe')
iframe.src = 'http://xxxx.com/post.html'
document.body.appendChild(iframe)

window.addEventListener('message', function(e) {   //監(jiān)聽消息,接受子頁面數(shù)組
  console.log(JSON.parse(e.data))
  //可將數(shù)據(jù)處理后再傳給子頁面
  //var data = e.data;
  //data.name = 'a';
  //iframe.contentWindow.postMessage(JSON.stringify(data), 'http://xxxx.com');
}, false);

post.html

var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        parent.postMessage(xhr.responseText, '*') //子窗口向父窗口發(fā)信息
        //postMessage(具體的信息內(nèi)容, origin)    
        //origin可以是‘協(xié)議 + 域名 + 端口’翩活;也可以是*,表示可以傳遞給任意窗口便贵;或者‘/’表示和當(dāng)前窗口同源
    }
}
xhr.open('GET', 'http://xxxx.com/json', true)  //獲取數(shù)據(jù)
xhr.send(null)
  1. WebSocket
    WebSocket是HTML5一種新的協(xié)議菠镇,不實(shí)行同源策略。
    可以用WebSocket+SockJS+Stomp或者WebSocket+SockJS
  2. nginx反向代理
    服務(wù)器端調(diào)用HTTP接口只是使用HTTP協(xié)議承璃,不會執(zhí)行JS腳本利耍,不需要同源策略。
    實(shí)現(xiàn):通過nginx配置一個(gè)代理服務(wù)器(域名與domain1相同盔粹,端口不同)做中轉(zhuǎn)隘梨,反向代理訪問domain2接口,還可以順便修改cookie中domain信息舷嗡。
    此方法可以不用目標(biāo)服務(wù)器配合轴猎,是成本比較低的一種方法。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末进萄,一起剝皮案震驚了整個(gè)濱河市捻脖,隨后出現(xiàn)的幾起案子锐峭,更是在濱河造成了極大的恐慌,老刑警劉巖可婶,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沿癞,死亡現(xiàn)場離奇詭異,居然都是意外死亡矛渴,警方通過查閱死者的電腦和手機(jī)椎扬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來具温,“玉大人蚕涤,你說我怎么就攤上這事」瘐铮” “怎么了钻趋?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剂习。 經(jīng)常有香客問我蛮位,道長,這世上最難降的妖魔是什么鳞绕? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任失仁,我火速辦了婚禮,結(jié)果婚禮上们何,老公的妹妹穿的比我還像新娘萄焦。我一直安慰自己,他們只是感情好冤竹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布拂封。 她就那樣靜靜地躺著,像睡著了一般鹦蠕。 火紅的嫁衣襯著肌膚如雪冒签。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天钟病,我揣著相機(jī)與錄音萧恕,去河邊找鬼。 笑死肠阱,一個(gè)胖子當(dāng)著我的面吹牛票唆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屹徘,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼走趋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了噪伊?” 一聲冷哼從身側(cè)響起吆视,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤典挑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后啦吧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體您觉,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年授滓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了琳水。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡般堆,死狀恐怖在孝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情淮摔,我是刑警寧澤私沮,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站和橙,受9級特大地震影響仔燕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜魔招,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一晰搀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧办斑,春花似錦外恕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蠕蚜,卻和暖如春尚洽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背波势。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工翎朱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橄维,地道東北人尺铣。 一個(gè)月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像争舞,于是被迫代替她去往敵國和親凛忿。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

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

  • 什么是跨域竞川? 2.) 資源嵌入:店溢、叁熔、、等dom標(biāo)簽床牧,還有樣式中background:url()荣回、@font-fac...
    電影里的夢i閱讀 2,377評論 0 5
  • 原文地址:原文地址 什么是跨域? 跨域是指一個(gè)域下的文檔或腳本試圖去請求另一個(gè)域下的資源戈咳,這里跨域是廣義的心软。 廣義...
    C_Y大漁閱讀 1,259評論 1 13
  • 1. 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本著蛙。它是由瀏覽器的同源策略造成的删铃,是瀏覽器對JavaScri...
    cbw100閱讀 6,339評論 2 86
  • <轉(zhuǎn)>詳解跨域(最全的解決方案) 什么是跨域跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本踏堡。它是由瀏覽器的同源策略造成的猎唁,...
    涅槃快樂是金閱讀 4,754評論 0 3
  • 【親愛的诫隅,不要跨過那條江】 催淚迷必備紀(jì)錄片,樸實(shí)溫馨慕的,情深動人阎肝。其名字來感于自韓國人盡皆知的詩歌[您別再過這條河...
    愿水閱讀 268評論 0 0