跨域的幾種方法

什么是跨域

說到跨域必須先解釋什么是同源策略,它是由Netscape提出的一個著名的安全策略。瀏覽器出于安全方面的考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方的資源?,F在所有支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。

首先我們來復習下一個完整的url組成

https://www.baidu.com:8080/aaa/1.html?id=10#name
window.location.portocol = https;   //協議
window.location.host = www.baidu.com:8080;   //域名
window.location.hostName = www.baidu.com;   
window.location.port = 8080;  //端口
window.location.search = ?id=10;
window.location.hash = #name;

還不是很熟悉的小伙伴可以參考下什么是域名?什么網站名?什么是URL?,搞懂這個才能理解好同源策略和跨域。
舉例:

同源:
http://jirengu.com/a/b.js 和 http://jirengu.com/index.php 
不同源
http://jirengu.com/main.js 和 https://jirengu.com/a.php (協議不同)
http://jirengu.com/main.js 和 http://bbs.jirengu.com/a.php (域名不同,域名必須完全相同才可以)
http://jiengu.com/main.js 和 http://jirengu.com:8080/a.php (端口不同,第一個是80)

**需要注意的是: 對于當前頁面來說頁面存放的 JS 文件的域不重要,重要的是加載該 JS 頁面所在什么域 **

實際中我們經常需要到不同的域名下獲得數據,由于同源策略的存在我們無法通過AJAX等方式直接獲取數據 ,需要一些方法來實現跨域,主要的跨域方式有

  • jsonp
  • CORS (cross-origin-resource-shareing //iE10及以上支持)
  • 降域 (具有局限性,只有是同屬于一個域名的二級域名還能夠使用這種方式)
  • postMessage

下面就具體介紹下每一種跨域方式

1、jsonp

JSONP 的原理是script標簽的src屬性不受同源策略影響,網頁通過添加一個元素,相當于向服務器發送了一個get請求,服務器收到請求后,將數據放在一個指定名字的回調函數里傳回來。
舉一個簡單的例子
在目錄下建立個名稱為 1的txt文件,內容為 123,在index.html中使用srcipt標簽請求文本文件

文件目錄

打開控制臺查看請求,在Response中我們成功的拿到1.txt中的數據123。但是,我們雖然拿到了數據但卻沒有辦法使用~!??!這時候有人就想到了用函數調用方式,將服務器傳過來的數據以函數參數的方式調用

修改文本中的數據

相當于這種寫法

這里就相當于調用了函數fn,實際中調用的這個函數名也事先約定好的,發送請求實際上就是利用DOM操作在文檔中添加一個script標簽請求數據,注意這個請求的標簽在請求完成后要刪除

一個完整的JSONP例子

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>example</title>
    <style media="screen">
      .newsFrame{
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <div class="newsFrame">
      <ul class="content">
        <li>上學</li>
        <li>消費</li>
        <li>生活</li>
      </ul>
      <button class="btn">換一批</button>
    </div>


     <script type="text/javascript">
        $('.btn').addEventListener('click',function(){
          var script = document.createElement('script');
          script.src='http://b.har.com:8080/getNews?callback=appendhtml';

          document.head.appendChild(script);
          document.head.removeChild(script);
        })

      function appendhtml(news){
        var html = '';
        for(var i=0; i<news.length; i++){
          html += '<li>' + news[i] + '</li>'
        }
        console.log(html)
      $('.content').innerHTML = html
      }

      function $(id){
        return document.querySelector(id)
      }

    </script>
  </body>
</html>

后端

   app.get('/getNews', function(req, res) {
        var news = [
        "看電視",
        '大學在學習',
        '大家在跑步',
        '天氣預報',
        '我要吃飯',
        '看電視'
      ]
      var data = [];
      for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
      news.splice(index,1);
      }
    var cb = req.query.callback;
      res.send( cb + '(' + JSON.stringify(data) + ')' );
    });

最后,JS中還有其他三個標簽可以進行跨域請求img 、iframe、link(stylesheet)但他們都有缺陷

      img  
  //支持跨域但是無法實現獲取服務端返回的數據
  <iframe src="https://www.baidu.com"></iframe>
  //支持跨域,可以接收服務端數據,但是過程復雜
  <link rel="stylesheet" type="text/css" >
  //會在CSS處理階段報錯

2、CORS

CORS全稱跨域資源共享(crossing-origin resourse sharing),是一種ajax跨域 請求資源的方式,支持現代瀏覽器,支持IE10以上。實現的方式很簡單,當你使用XMLHttpRequest發送請求時,瀏覽器發現該請求不符合同源策略,會給該請求加一個請求頭:Origin,后臺進行一系列處理,如果確定接受請求則在返回的結果中加入一個響應頭:Access-Control-Allow-Origin;瀏覽器判斷響應頭中是否包含Origin的值,如果有則瀏覽器會處理響應,我們就可以拿到響應數據,如果不包含瀏覽器直接駁回,這時我們無法拿到響應數據。所以,CORS的表象是讓你覺得他與同源的AJAX的請求沒啥區別,代碼完全一樣。

node的服務端

   app.get('/getNews', function(req, res) {
        var news = [
        "看電視",
        '大學在學習',
        '大家在跑步',
        '天氣預報',
        '我要吃飯',
        '看電視'
      ]
      var data = [];
      for(var i=0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index]);
      news.splice(index,1);
      }
      res.header("Access-Control-Allow-Origin","http://a.jrg.com:8080");//CORS
      //res.header("Access-Control-Allow-Origin","*");
      res.send( data );
    });

深入學習可以參考阮一峰老師的博客CORS

3、降域

降域主要應用在域名相同的網站之間的跨域。

舉個例子

http://a.jrg.com:8080/a.html
http://b.jrg.com:8080/a.html

根據同源策略上面的兩個網址是不是本域,但他們的域名相同,都是jrg.com所以可以通過降域的方式跨域 。具體的實現方法分別在對應的網頁的JS中加入

document.domain = "jrg.com";

4、postMessage

postMessage作為html5新引入的API允許來自不同源的腳本采用異步方式進行有限的通信,可以實現跨文本檔、多窗口、跨域消息傳遞。

語法

1、發送

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

  • otherWindow
    其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。
  • message
    將要發送到其他 window的數據。它將會被[結構化克隆算法序列化。這意味著你可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化。
  • targetOrigin
    通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串""(表示無限制)或者一個URI。在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那么消息就不會被發送;只有三者完全匹配,消息才會被發送。這個機制用來控制消息可以發送到哪些窗口;例如,當用postMessage傳送密碼時,這個參數就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預期接受者的orign屬性完全一致,來防止密碼被惡意的第三方截獲。如果你明確的知道消息應該發送到哪個窗口,那么請始終提供一個有確切值的targetOrigin,而不是。不提供確切的目標將導致數據泄露到任何對數據感興趣的惡意站點。
  • transfer
    可選是一串和message 同時傳遞的 Transferable
    對象. 這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權。

2、監聽
執行如下代碼, 其他window可以監聽派遣的message:

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  // For Chrome, the origin property is in the event.originalEvent
  // object.
  var origin = event.origin || event.originalEvent.origin; 
  if (origin !== "http://example.org:8080")
    return;

  // ...
}

message 的屬性有:

  • data
    從其他 window 中傳遞過來的對象。
  • origin
    調用 postMessage時消息發送方窗口的 origin。這個字符串由 協議、“://“、域名、“ : 端口號”拼接而成。
  • source
    對發送消息的窗口對象的引用; 您可以使用此來在具有不同origin的兩個窗口之間建立雙向通信。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 什么是跨域 瀏覽器出于安全方面的考慮,只允許客戶端與本域(同協議、同域名、同端口,三者缺一不可)下的接口交互。不同...
    七里之境閱讀 1,367評論 0 0
  • CORS 實現CORS需要瀏覽器和服務器的共同協作。對于前端開發者來說,CORS通信與同源的AJAX在代碼方面沒有...
    饑人谷_有點熱閱讀 1,300評論 0 2
  • 1. AJAX AJAX(Asynchronous JavaScript and XML),意思就是用JavaSc...
    公子七閱讀 5,029評論 0 5
  • 概念:只要協議、域名、端口有任何一個不同,都被當作是不同的域。 所有具有 src 屬性的HTML標簽都可以跨域 原...
    jeffAAA閱讀 2,578評論 0 0
  • 同源策略 瀏覽器出于安全方面的考慮,為了保證用戶信息的安全,防止惡意的網站竊取數據。只允許與本域下的接口交互。不同...
    祝余_scrapy閱讀 408評論 0 0