跨域

1: 什么是同源策略

同源策略(Same origin Policy),瀏覽器出于安全方面的考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授權的情況下,不能讀寫對方的資源。
本域指的是:

  • 同協議:如都是http或者https
  • 同域名:如都是http:// jirengu.com/a 和http:// jirengu.com/b
  • 同端口:如都是80端口
    例子:
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)

2: 什么是跨域?跨域有幾種實現形式

跨域就是實現不同域之間的相互訪問。

  1. JSONP
  2. CORS(用了ajax)
  3. 降域
  4. postMessage

下面將開始分別講解四種方式:

JSONP

jsonp是json with padding(填充式json或參數式json)的簡寫。html中script標簽可以引入其他域下的js,比如引入線上的jquery庫。利用這個特性,可實現跨域訪問接口,需要后端支持。其中src的鏈接會被當成js執行。

  1. 定義數據處理函數_fun
  2. 創建script標簽,src的地址執行后端接口,最后加個參數callback=_fun
  3. 服務端在收到請求后,解析參數,計算返回數據,輸出fun(data)字符串。
  4. fun(data)會放到script標簽作為js執行。此時會調用fun函數,將data作為參數,所以我們無需再執行fun()函數,因為再script標簽中會執行
<!-- 直接file中打開此文件,打開服務端,模仿跨域 -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>news</title>
  <style>
  .contain {
     width: 900px;
     margin: 0 auto;
  }
  </style>
</head>
<body>
  <div class="contain">
    <ul class="news">
      <li>第11日前瞻:中國沖擊4金 博爾特再戰</li>
      <li>男雙力爭會師決賽</li>
      <li>女排將死磕巴西!</li>
    </ul>
    <button class="change">換一組</button>
  </div>
  <script type="text/javascript">
    $('.change').addEventListener('click',function(){
        var script = document.createElement('script');
        script.src = 'http://localhost:8080/getNews?callback=appendHtml';
        document.head.appendChild(script);
        document.head.removeChild(script);
    })
    function appendHtml(news){
        var html = '';
        for (var i = news.length - 1; i >= 0; i--) {
            html += '<li>' + news[i] + '</li>';
        }
        $('.news').innerHTML = html;
    }
    function $(id){
        return document.querySelector(id);
    }
  </script>
</body>
</html>


app.get('/getNews', function(req, res){

    var news = [
        "第11日前瞻:中國沖擊4金 博爾特再戰200米羽球",
        "正直播柴飚/洪煒出戰 男雙力爭會師決賽",
        "女排將死磕巴西!郎平安排男陪練模仿對方核心",
        "沒有中國選手和巨星的110米欄 我們還看嗎?",
        "中英上演奧運金牌大戰",
        "博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多",
        "最“出柜”奧運?同性之愛閃耀里約",
        "下跪拜謝與洪荒之力一樣 都是真情流露"
    ]
    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;
    if(cb){
        res.send(cb + '('+ JSON.stringify(data) + ')');
    }else{
        res.send(data);
    }
    //appendHtml(['1xxx','2xxx'])
})

cors

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

<!-- 為了模仿跨域,我們將設置a.jrg.com和b.jrg.com他倆都指向127.0.0.1,這樣我們
在 a.jrg.com:8080打開網頁,向b.jrg.com發送請求。-->
<!--html和上面一樣 -->
  <script type="text/javascript">
    $('.change').addEventListener('click',function(){
        var xhr = new XMLHttpRequest();
      xhr.open('get','http://b.jrg.com:8080/getNews',true);
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status === 200 || xhr.statue === 304){
            var result = JSON.parse(xhr.responseText);
            appendHtml(result);
          }
        }
      }
    })
    function appendHtml(news){               
        var html = '';
        for (var i = news.length - 1; i >= 0; i--) {
            html += '<li>' + news[i] + '</li>';
        }
        $('.news').innerHTML = html;
    }
    function $(id){
        return document.querySelector(id);
    }
  </script>
</body>
</html>
app.get('/getNews', function(req, res){
    var news = [
        "第11日前瞻:中國沖擊4金 博爾特再戰200米羽球",
        "正直播柴飚/洪煒出戰 男雙力爭會師決賽",
        "女排將死磕巴西!郎平安排男陪練模仿對方核心",
        "沒有中國選手和巨星的110米欄 我們還看嗎?",
        "中英上演奧運金牌大戰",
        "博彩賠率挺中國奪回第二紐約時報:中國因對手服禁藥而丟失的獎牌最多",
        "最“出柜”奧運?同性之愛閃耀里約",
        "下跪拜謝與洪荒之力一樣 都是真情流露"
    ]
    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');  
    //res.header('Access-Control-Allow-Origin','*');
    res.send(data);
})

降域

降域是相對于iframe元素而言的 。
一般來說域名為http:// b.jrg.com/b的網頁以iframe的形式嵌在域名為http:// a.jrg.com/a的網頁中,瀏覽器發現該請求不符合同源策略,正常情況下不能進行跨域訪問,但是當我們在兩個頁面中分別設置documet.domain = jrg.com的時候(注意觀察這個方法有一個限制就是 域名中必須有相同的部分),B頁面就可以訪問到A頁面中的資源了,比如下面的代碼:

<html>
<head>
  <meta charset="utf-8">
</head>
<style>
  .ct{
    width: 910px;
    margin: auto;
  }
  .main{
    float: left;
    width: 450px;
    height: 300px;
    border: 1px solid #ccc;
  }
  .main input{
    margin: 20px;
    width: 200px;
  }
  .iframe{
    float: right;
  }

  iframe{
    width: 450px;
    height: 300px;
    border: 1px dashed #ccc;
  }
</style>
<div class="ct">
  <h1>使用降域實現跨域</h1>
  <div class="main">
    <input type="text" placeholder="http://a.jrg.com:8080/a.html">
  </div>
  <iframe src="http://b.jrg.com:8080/b.html" frameborder="0" ></iframe>
</div>
<script>
//URL: http://a.jrg.com:8080/a.html
document.querySelector('.main input').addEventListener('input',function(){
  console.log(this.value);
  window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = "jrg.com";        //降域
</script>
</html>
<html>
<head>
  <meta charset="utf-8">
</head>
<style>
    html,body{
        margin: 0;
    }
    input{
        margin: 20px;
        width: 200px;
    }
</style>
    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
<script>
// URL: http://b.jrg.com:8080/b.html
 document.querySelector('input').addEventListener('input',function(){
  console.log(this.value);
  window.parent.document.querySelector('.main input').value = this.value
})
document.domain = "jrg.com";       //降域
</script>
</html>

PostMessage

window.postMessage()是HTML5的新方法,可以使用它來向其它的window對象發送數據,無論這個window對象是屬于同源或不同源,IE8+支持。
otherWindow.postMessage(message, targetOrigin);

  • otherWindow
    其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。
  • message
    要傳遞的數據。html5規范中提到該參數可以是JavaScript的任意基本類型或可復制的對象,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數,所以我們在傳遞參數的時候需要使用JSON.stringify()方法對對象參數序列化.
  • 通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串""(表示無限制)或者一個URI。在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那么消息就不會被發送;只有三者完全匹配,消息才會被發送。這個機制用來控制消息可以發送到哪些窗口;例如,當用postMessage傳送密碼時,這個參數就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預期接受者的orign屬性完全一致,來防止密碼被惡意的第三方截獲。如果你明確的知道消息應該發送到哪個窗口,那么請始終提供一個有確切值的targetOrigin,而不是。不提供確切的目標將導致數據泄露到任何對數據感興趣的惡意站點。
//html同上
//a.html
<script>
//URL: http://a.jrg.com:8080/a.html
  $('.main input').addEventListener('input',function(){
    console.log(this.value);
    window.frames[0].postmessage(this.value,'*');
  });
  window.addEventListener('message',function(e){
    $('.main input') = e.data;
    console.log(e.data);
  });
  function $(id){
    return document.querySelector(id);
  }
</script>
<script>

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

推薦閱讀更多精彩內容

  • 什么是同源策略 同源政策(same-origin policy)是指同域名(或ip),同端口,同協議視為同一個域,...
    小囧兔閱讀 537評論 0 1
  • 什么是同源策略 瀏覽器出于安全方面的考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授權的情況下,不能...
    ezrealor閱讀 503評論 0 1
  • 什么是同源策略? 同源策略是指,瀏覽器出于安全方面的考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授...
    upup_dayday閱讀 265評論 0 0
  • 一、瀏覽器的同源策略 1.什么是同源? 所謂“同源”指的是”三個相同“。相同的域名、端口和協議,這三個相同的話就視...
    徐國軍_plus閱讀 860評論 1 3
  • 比鬼神更可怕的,是人心。
    嵐風的葉子閱讀 318評論 0 0