九種跨域解決方案

何為跨域

??想必大家都知道雄坪,不在贅述了厘熟,跨域問題出現(xiàn)的原因就是瀏覽器的安全機(jī)制:同協(xié)議、域名维哈、端口绳姨。下面就總結(jié)下常用的幾種解決方案。

1阔挠、JSONP(只能發(fā)送get請求飘庄,不支持post、put购撼、delete跪削;不安全xss攻擊)

??jsonp的詳細(xì)介紹在另一篇文章,這里就以百度的查詢接口做簡單展示:

<script>
// 封裝簡單的jsonp
function jsonp(url, params, cb) {
  return new Promise((resovle, reject) => {
    let script = document.creatElement('script');
    window[cb] = function(data) {
      resovle(data);
      document.body.removeChild(script);
    }
    params = {...params, cb}; //wd=b&cb=show
    let arrs = [];
    for(let key in params) {
      arrs.push(`${key}=${params[key]}`);
    }
    script.url =  `${url}?${arrs.join('&')}`;
    document.body.appendChild(script);
 })
}
// jsonp調(diào)用方式
jsonp({
  url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
  params:{wd: 'b'},
  cb: show
}).then(data=>{
  console.log(data)
})
</script>
2迂求、cors(后臺配置)

??下面以express為例

// 設(shè)置那些原可以訪問接口
res.setHeader('Access-Control-Allow-Origin', origin) 
// 允許攜帶哪個頭訪問
res.setHeader('Access-Control-Allow-Headers', 'name') 
// 允許那些請求方法
res.setHeader('Access-Control-Allow-Methods', 'PUT,POST,DELETE') 
// 允許攜帶cookie
res.setHeader('Access-Control-Allow-Credentials',true) 
// 預(yù)檢測存活時間(options請求)
res.setHeader('Access-Control-Max-Age',6000) 
// 允許前端獲取哪個請求頭(允許返回的頭)
res.setHeader('Access-Control-Expose-Header','name') 
3碾盐、iframe postMessage

??postMessage 是 HTML5 XMLHttpRequest Level 2 中的 API,且是為數(shù)不多可以跨域操作的 window 屬性之一揩局,它可用于解決以下方面的問題:

  • 頁面和其打開的新窗口的數(shù)據(jù)傳遞
  • 多窗口之間消息傳遞
  • 頁面與嵌套的 iframe 消息傳遞
  • 上面三個場景的跨域數(shù)據(jù)傳遞
    postMessage()方法允許來自不同源的腳本采用異步方式進(jìn)行有限的通信毫玖,可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞付枫。

otherWindow.postMessage(message, targetOrigin, [transfer]);

  • message: 將要發(fā)送到其他 window 的數(shù)據(jù)烹玉。
  • targetOrigin:通過窗口的 origin 屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個 URI阐滩。在發(fā)送消息的時候二打,如果目標(biāo)窗口的協(xié)議、主機(jī)地址或端口這三者的任意一項(xiàng)不匹配 targetOrigin 提供的值掂榔,那么消息就不會被發(fā)送继效;只有三者完全匹配,消息才會被發(fā)送衅疙。
  • transfer(可選):是一串和 message 同時傳遞的 Transferable 對象. 這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方莲趣,而發(fā)送一方將不再保有所有權(quán)鸳慈。
    接下來我們看個例子: http://localhost:3000/a.html頁面向http://localhost:4000/b.html傳遞“我愛你”,然后后者傳回"我不愛你"饱溢。
// a.html
  <iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe//等它加載完觸發(fā)一個事件
  //內(nèi)嵌在http://localhost:3000/a.html
    <script>
      function load() {
        let frame = document.getElementById('frame')
        frame.contentWindow.postMessage('我愛你', 'http://localhost:4000') //發(fā)送數(shù)據(jù)
        window.onmessage = function(e) { //接受返回數(shù)據(jù)
          console.log(e.data) //我不愛你
        }
      }
    </script>
// b.html
  window.onmessage = function(e) {
    console.log(e.data) //我愛你
    e.source.postMessage('我不愛你', e.origin)
 }
4、window.name

window.name 屬性的獨(dú)特之處:name 值在不同的頁面(甚至不同域名)加載后依舊存在走芋,并且可以支持非常長的 name 值(2MB)绩郎。
??a、b頁面同域翁逞,a頁面嵌套c頁面肋杖,onload事件第一次載入c頁面url變?yōu)閎頁面并且獲取contentWindow.name

 // a.html(http://localhost:3000/b.html)
  <iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
  <script>
    let first = true
    // onload事件會觸發(fā)2次,第1次加載跨域頁挖函,并留存數(shù)據(jù)于window.name
    function load() {
      if(first){
      // 第1次onload(跨域頁)成功后状植,切換到同域代理頁面
        let iframe = document.getElementById('iframe');
        iframe.src = 'http://localhost:3000/b.html';
        first = false;
      }else{
      // 第2次onload(同域b.html頁)成功后,讀取同域window.name中數(shù)據(jù)
        console.log(iframe.contentWindow.name);
      }
    }
  </script>
// c.html(http://localhost:4000/c.html)
  <script>
    window.name = '我不愛你'
  </script>
5怨喘、hash

??a中嵌套c津畸,c中嵌套b,a=>b=>c傳遞location.hash必怜,a頁面用window.onhashchange獲取hash值

// a.html
  <iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
  <script>
    window.onhashchange = function () { //檢測hash的變化
      console.log(location.hash);
    }
  </script>
 // b.html
  <script>
    window.parent.parent.location.hash = location.hash
    //b.html將結(jié)果放到a.html的hash值中肉拓,b.html可通過parent.parent訪問a.html頁面
  </script>
 // c.html
 console.log(location.hash);
  let iframe = document.createElement('iframe');
  iframe.src = 'http://localhost:3000/b.html#idontloveyou';
  document.body.appendChild(iframe);
6、document.domain

??必須是一級域名和二級域名的關(guān)系

// a.html
<body>
 helloa
  <iframe src="http://b.zf1.cn:3000/b.html" frameborder="0" onload="load()" id="frame"></iframe>
  <script>
    document.domain = 'zf1.cn'
    function load() {
      console.log(frame.contentWindow.a);
    }
  </script>
</body>
// b.html
<body>
   hellob
   <script>
     document.domain = 'zf1.cn'
     var a = 100;
   </script>
</body>
7梳庆、websocket

可以參考阮大的文章暖途。

// socket.html
<script>
    let socket = new WebSocket('ws://localhost:3000');
    socket.onopen = function () {
      socket.send('我愛你');//向服務(wù)器發(fā)送數(shù)據(jù)
    }
    socket.onmessage = function (e) {
      console.log(e.data);//接收服務(wù)器返回的數(shù)據(jù)
    }
</script>
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');//記得安裝ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
  ws.on('message', function (data) {
    console.log(data);
    ws.send('我不愛你')
  });
})
8、ngxin

實(shí)現(xiàn)原理類似于 Node 中間件代理膏执,需要你搭建一個中轉(zhuǎn) nginx 服務(wù)器驻售,用于轉(zhuǎn)發(fā)請求。

使用 nginx 反向代理實(shí)現(xiàn)跨域更米,是最簡單的跨域方式欺栗。只需要修改 nginx 的配置即可解決跨域問題,支持所有瀏覽器,支持 session纸巷,不需要修改任何代碼镇草,并且不會影響服務(wù)器性能。

實(shí)現(xiàn)思路:通過 nginx 配置一個代理服務(wù)器(域名與 domain1 相同瘤旨,端口不同)做跳板機(jī)梯啤,反向代理訪問 domain2 接口,并且可以順便修改 cookie 中 domain 信息存哲,方便當(dāng)前域 cookie 寫入因宇,實(shí)現(xiàn)跨域登錄。

先下載nginx祟偷,然后將 nginx 目錄下的 nginx.conf 修改如下:

// proxy服務(wù)器
server {
    listen       80;
    server_name  www.domain1.com;
    location / {
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;

        # 當(dāng)用webpack-dev-server等中間件代理接口訪問nignx時察滑,此時無瀏覽器參與,故沒有同源限制修肠,下面的跨域配置可不啟用
        add_header Access-Control-Allow-Origin http://www.domain1.com;  #當(dāng)前端只跨域不帶cookie時贺辰,可為*
        add_header Access-Control-Allow-Credentials true;
    }
}
9、webpack proxy
//服務(wù)器啟動目錄;
  devServer: {
    contentBase: './dist',
    hot: true,
    // host:'1ocalhost',
    port: 8586,
    // compress:true,

    //解決跨域
    proxy: {
      '/api': {
        target: 'http://localhost:8087',
        pathRewrite: { '^/api': '' },
        changeOrigin: true,
        secure: false, // 接受 運(yùn)行在 https 上的服務(wù)
      }
    }
  },
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嵌施,一起剝皮案震驚了整個濱河市饲化,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吗伤,老刑警劉巖吃靠,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異足淆,居然都是意外死亡巢块,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門巧号,熙熙樓的掌柜王于貴愁眉苦臉地迎上來族奢,“玉大人,你說我怎么就攤上這事裂逐〈跤悖” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵卜高,是天一觀的道長弥姻。 經(jīng)常有香客問我,道長掺涛,這世上最難降的妖魔是什么庭敦? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮薪缆,結(jié)果婚禮上秧廉,老公的妹妹穿的比我還像新娘伞广。我一直安慰自己,他們只是感情好疼电,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布嚼锄。 她就那樣靜靜地躺著,像睡著了一般蔽豺。 火紅的嫁衣襯著肌膚如雪区丑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天修陡,我揣著相機(jī)與錄音沧侥,去河邊找鬼。 笑死魄鸦,一個胖子當(dāng)著我的面吹牛宴杀,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拾因,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼旺罢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盾致?” 一聲冷哼從身側(cè)響起主经,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤荣暮,失蹤者是張志新(化名)和其女友劉穎庭惜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體穗酥,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡护赊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了砾跃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骏啰。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抽高,靈堂內(nèi)的尸體忽然破棺而出判耕,到底是詐尸還是另有隱情,我是刑警寧澤翘骂,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布壁熄,位于F島的核電站,受9級特大地震影響碳竟,放射性物質(zhì)發(fā)生泄漏草丧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一莹桅、第九天 我趴在偏房一處隱蔽的房頂上張望昌执。 院中可真熱鬧,春花似錦、人聲如沸懂拾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岖赋。三九已至呜师,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贾节,已是汗流浹背汁汗。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栗涂,地道東北人知牌。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像斤程,于是被迫代替她去往敵國和親角寸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

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