進(jìn)階13-JSONP跨域

1.什么是同源策略
瀏覽器出于安全方面的考慮暂幼,只允許與本域下的接口交互。不同源的客戶端腳本在沒(méi)有明確授權(quán)的情況下,不能讀寫對(duì)方的資源核芽。

  • 同協(xié)議:如都是http或者h(yuǎn)ttps
  • 同域名:如都是http://jirengu.com/a 和-http://jirengu.com/b
  • 同端口:如都是80端口
    需要注意的是: 對(duì)于當(dāng)前頁(yè)面來(lái)說(shuō)頁(yè)面存放的 JS 文件的域不重要妖谴,重要的是加載該 JS 頁(yè)面所在什么域

2.
什么是跨域
跨域是指從一個(gè)域名的網(wǎng)頁(yè)去請(qǐng)求另一個(gè)域名的資源窿锉。嚴(yán)格的定義是:只要不符合同源政策的任意一條,就被當(dāng)作跨域膝舅。

為什么瀏覽器要限制跨域
原因就是安全問(wèn)題:如果一個(gè)網(wǎng)頁(yè)可以隨意的訪問(wèn)另外一個(gè)網(wǎng)站的資源嗡载,那么就有可能在客戶完全不知情的情況下出現(xiàn)安全問(wèn)題。

跨域的實(shí)現(xiàn)形式
同源政策做的限制:
(1) Cookie仍稀、LocalStorage 和 IndexDB 無(wú)法讀取洼滚。
(2) DOM 無(wú)法獲得。
(3) AJAX 請(qǐng)求不能發(fā)送技潘。
關(guān)于Cookie:
兩個(gè)網(wǎng)頁(yè)一級(jí)域名相同遥巴,只是二級(jí)域名不同千康,瀏覽器允許通過(guò)設(shè)置document.domain共享 Cookie。
A網(wǎng)頁(yè)通過(guò)腳本設(shè)置一個(gè)cookie

document.cookie = "test1=hello";

B網(wǎng)頁(yè)就可以讀到這個(gè) Cookie挪哄。

var allCookie = document.cookie;

注意吧秕,這種方法只適用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexDB 無(wú)法通過(guò)這種方法,規(guī)避同源政策迹炼,而要使用下文介紹的PostMessage API砸彬。

服務(wù)器也可以在設(shè)置Cookie的時(shí)候,指定Cookie的所屬域名為一級(jí)域名

Set-Cookie: key=value; domain=.example.com; path=/

關(guān)于iframe
如果兩個(gè)網(wǎng)頁(yè)不同源斯入,就無(wú)法拿到對(duì)方的DOM砂碉。典型的例子是iframe窗口和window.open方法打開的窗口,它們與父窗口無(wú)法通信刻两。

document.getElementById("myIFrame").contentWindow.document
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.

上面命令中增蹭,父窗口想獲取子窗口的DOM,因?yàn)榭缭磳?dǎo)致報(bào)錯(cuò)磅摹。
反之亦然滋迈,子窗口獲取主窗口的DOM也會(huì)報(bào)錯(cuò)。

window.parent.document.body
// 報(bào)錯(cuò)

對(duì)于完全不同源的網(wǎng)站户誓,目前有三種方法饼灿,可以解決跨域窗口的通信問(wèn)題。

1.片段識(shí)別符(fragment identifier)
2.window.name
3.跨文檔通信API(Cross-document messaging)

破解方法:
1.片段識(shí)別符
片段標(biāo)識(shí)符(fragment identifier)指的是帝美,URL的#號(hào)后面的部分碍彭,比如http://example.com/x.html#fragment的#fragment。如果只是改變片段標(biāo)識(shí)符悼潭,頁(yè)面不會(huì)重新刷新庇忌。
父窗口可以把信息,寫入子窗口的片段標(biāo)識(shí)符舰褪。

var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

子窗口通過(guò)監(jiān)聽hashchange事件得到通知皆疹。

window.onhashchange = checkMessage;

function checkMessage() {
  var message = window.location.hash;
  // ...
}

同樣的,子窗口也可以改變父窗口的片段標(biāo)識(shí)符占拍。

parent.location.href= target + "#" + hash;

2.window.name
瀏覽器窗口有window.name屬性墙基。這個(gè)屬性的最大特點(diǎn)是,無(wú)論是否同源刷喜,只要在同一個(gè)窗口里残制,前一個(gè)網(wǎng)頁(yè)設(shè)置了這個(gè)屬性,后一個(gè)網(wǎng)頁(yè)可以讀取它掖疮。
父窗口先打開一個(gè)子窗口初茶,載入一個(gè)不同源的網(wǎng)頁(yè),該網(wǎng)頁(yè)將信息寫入window.name屬性。

window.name = data;

接著恼布,子窗口跳回一個(gè)與主窗口同域的網(wǎng)址螺戳。

location = '[http://parent.url.com/xxx.html](http://parent.url.com/xxx.html)';

主窗口就可以讀取子窗口的window.name

var data = document.getElementById('myFrame').contentWindow.name;

這種方法的優(yōu)點(diǎn)是,window.name容量很大折汞,可以放置非常長(zhǎng)的字符串倔幼;缺點(diǎn)是必須監(jiān)聽子窗口window.name屬性的變化,影響網(wǎng)頁(yè)性能爽待。
3.window.postMessage
允許跨窗口通信损同,不論這兩個(gè)窗口是否同源。
舉例來(lái)說(shuō)鸟款,父窗口http://aaa.com向子窗口http://bbb.com發(fā)消息膏燃,調(diào)用postMessage方法就可以了。

var popup = window.open('[http://bbb.com](http://bbb.com/)', 'title');
popup.postMessage('Hello World!', '[http://bbb.com](http://bbb.com/)');

postMessage方法的第一個(gè)參數(shù)是具體的信息內(nèi)容何什,第二個(gè)參數(shù)是接收消息的窗口的源(origin)组哩,即"協(xié)議 + 域名 + 端口"。也可以設(shè)為*处渣,表示不限制域名伶贰,向所有窗口發(fā)送。
子窗口向父窗口發(fā)送消息

window.opener.postMessage('Nice to see you', '[http://aaa.com](http://aaa.com/)');

父窗口和子窗口都可以通過(guò)message事件罐栈,監(jiān)聽對(duì)方的消息黍衙。

window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

message事件的事件對(duì)象event,提供以下三個(gè)屬性悠瞬。

event.source:發(fā)送消息的窗口
event.origin: 消息發(fā)向的網(wǎng)址
event.data: 消息內(nèi)容

下面的例子是们豌,子窗口通過(guò)event.source屬性引用父窗口涯捻,然后發(fā)送消息浅妆。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
  event.source.postMessage('Nice to see you!', '*');
}

event.origin屬性可以過(guò)濾不是發(fā)給本窗口的消息。

window.addEventListener('message', receiveMessage);
function receiveMessage(event) { 
  if (event.origin !== '[http://aaa.com](http://aaa.com/)') return; 
  if (event.data === 'Hello World') {     event.source.postMessage('Hello', event.origin); 
  } else { console.log(event.data); 
  }
}

4.LocalStorage
通過(guò)window.postMessage障癌,讀寫其他窗口的 LocalStorage 也成為了可能凌外。
下面是一個(gè)例子,主窗口寫入iframe子窗口的localStorage涛浙。

window.onmessage = function(e) {
  if (e.origin !== '[http://bbb.com](http://bbb.com/)') { return; } 
  var payload = JSON.parse(e.data);
  localStorage.setItem(payload.key,
  JSON.stringify(payload.data));
};

上面代碼中康辑,子窗口將父窗口發(fā)來(lái)的消息,寫入自己的LocalStorage轿亮。
父窗口發(fā)送消息的代碼如下疮薇。

var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack};
win.postMessage(JSON.stringify({key: 'storage', data: obj}), 
'[http://bbb.com](http://bbb.com/)');

加強(qiáng)版的子窗口接收消息的代碼如下。

window.onmessage = function(e) { 
  if (e.origin !== '[http://bbb.com](http://bbb.com/)') return; 
  var payload = JSON.parse(e.data); 
  switch (payload.method) { 
    case 'set': 
      localStorage.setItem(payload.key, JSON.stringify(payload.data)); 
      break; 
    case 'get':
      var parent = window.parent; 
      var data = localStorage.getItem(payload.key); 
      parent.postMessage(data, '[http://aaa.com](http://aaa.com/)');
      break; 
    case 'remove': 
      localStorage.removeItem(payload.key); 
      break; }
};

加強(qiáng)版的父窗口發(fā)送消息代碼如下我注。

var win = document.getElementsByTagName('iframe')[0].contentWindow;
var obj = { name: 'Jack' };
// 存入對(duì)象
win.postMessage(JSON.stringify({key: 'storage', method: 'set', data: obj}), '[http://bbb.com](http://bbb.com/)');
// 讀取對(duì)象
win.postMessage(JSON.stringify({key: 'storage', method: "get"}), "*");
window.onmessage = function(e) {
 if (e.origin != '[http://aaa.com](http://aaa.com/)') return;  
// "Jack" 
console.log(JSON.parse(e.data).name);};

3.JSONP 的原理是什么
JSONP是服務(wù)器與客戶端跨源通信的常用方法按咒。最大特點(diǎn)就是簡(jiǎn)單適用,老式瀏覽器全部支持但骨,服務(wù)器改造非常小励七。
它的基本思想是智袭,網(wǎng)頁(yè)通過(guò)添加一個(gè)<script>元素,向服務(wù)器請(qǐng)求JSON數(shù)據(jù)掠抬,這種做法不受同源政策限制吼野;服務(wù)器收到請(qǐng)求后,將數(shù)據(jù)放在一個(gè)指定名字的回調(diào)函數(shù)里傳回來(lái)两波。不過(guò)它只能發(fā)get請(qǐng)求瞳步。
首先,網(wǎng)頁(yè)動(dòng)態(tài)插入<script>元素雨女,由它向跨源網(wǎng)址發(fā)出請(qǐng)求谚攒。

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://example.com/ip](http://example.com/ip)?callback=foo');    
                                                      //回調(diào)函數(shù)callback
}
function foo(data) { 
  console.log('Your public IP address is: ' + data.ip);
};

上面代碼通過(guò)動(dòng)態(tài)添加<script>元素,向服務(wù)器example.com發(fā)出請(qǐng)求氛堕。注意馏臭,該請(qǐng)求的查詢字符串有一個(gè)callback參數(shù),用來(lái)指定回調(diào)函數(shù)的名字讼稚,這對(duì)于JSONP是必需的括儒。
服務(wù)器收到這個(gè)請(qǐng)求以后,會(huì)將數(shù)據(jù)放在回調(diào)函數(shù)的參數(shù)位置返回锐想。

foo({
  "ip": "8.8.8.8"
});

由于<script>元素請(qǐng)求的腳本帮寻,直接作為代碼運(yùn)行。這時(shí)赠摇,只要瀏覽器定義了foo函數(shù)固逗,該函數(shù)就會(huì)立即調(diào)用。作為參數(shù)的JSON數(shù)據(jù)被視為JavaScript對(duì)象藕帜,而不是字符串烫罩,因此避免了使用JSON.parse的步驟。

4.CORS是什么
CORS是跨源資源分享(Cross-Origin Resource Sharing)的縮寫洽故。它是W3C標(biāo)準(zhǔn)贝攒,是跨源AJAX請(qǐng)求的根本解決方法。相比JSONP只能發(fā)GET請(qǐng)求时甚,CORS允許任何類型的請(qǐng)求隘弊。

CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前荒适,所有瀏覽器都支持該功能梨熙,IE瀏覽器不能低于IE10。

對(duì)于開發(fā)者來(lái)說(shuō)刀诬,CORS通信與同源的AJAX通信沒(méi)有差別咽扇,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息肌割,有時(shí)還會(huì)多出一次附加的請(qǐng)求卧蜓,但用戶不會(huì)有感覺。
因此把敞,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器弥奸。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信奋早。

瀏覽器將CORS請(qǐng)求分成兩類:簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)
只要同時(shí)滿足以下兩大條件盛霎,就屬于簡(jiǎn)單請(qǐng)求。

(1) 請(qǐng)求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded耽装、
              multipart/form-data愤炸、text/plain

凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求掉奄。
瀏覽器對(duì)這兩種請(qǐng)求的處理规个,是不一樣的。
對(duì)于簡(jiǎn)單請(qǐng)求姓建,瀏覽器直接發(fā)出CORS請(qǐng)求
就是在頭信息之中诞仓,增加一個(gè)Origin字段

GET /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面的頭信息中,Origin字段用來(lái)說(shuō)明速兔,本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 域名 + 端口)墅拭。服務(wù)器根據(jù)這個(gè)值,決定是否同意這次請(qǐng)求涣狗。
如果Origin指定的源谍婉,不在許可范圍內(nèi),服務(wù)器會(huì)返回一個(gè)正常的HTTP回應(yīng)镀钓。瀏覽器發(fā)現(xiàn)穗熬,這個(gè)回應(yīng)的頭信息沒(méi)有包含Access-Control-Allow-Origin字段(詳見下文),就知道出錯(cuò)了掸宛,從而拋出一個(gè)錯(cuò)誤死陆,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲招拙。注意唧瘾,這種錯(cuò)誤無(wú)法通過(guò)狀態(tài)碼識(shí)別,因?yàn)镠TTP回應(yīng)的狀態(tài)碼有可能是200别凤。
如果Origin指定的域名在許可范圍內(nèi)饰序,服務(wù)器返回的響應(yīng),會(huì)多出幾個(gè)頭信息字段规哪。

//該字段必須求豫,值為origin或者"*"
Access-Control-Allow-Origin: [http://api.bob.com](http://api.bob.com/)

/*
該字段可選,表示是否允許發(fā)送Cookie,該值默認(rèn)為true,
如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可蝠嘉。
*/
Access-Control-Allow-Credentials: true

//該字段可選最疆,如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

上面的頭信息之中蚤告,有三個(gè)與CORS請(qǐng)求相關(guān)的字段努酸,都以Access-Control-開頭。

非簡(jiǎn)單請(qǐng)求
1.預(yù)檢請(qǐng)求
非簡(jiǎn)單請(qǐng)求是那種對(duì)服務(wù)器有特殊要求的請(qǐng)求杜恰,比如請(qǐng)求方法是PUT或DELETE获诈,或者Content-Type字段的類型是application/json。

var url = '[http://api.alice.com/cors](http://api.alice.com/cors)';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

上面代碼中心褐,HTTP請(qǐng)求的方法是PUT舔涎,并且發(fā)送一個(gè)自定義頭信息X-Custom-Header。
瀏覽器發(fā)現(xiàn)逗爹,這是一個(gè)非簡(jiǎn)單請(qǐng)求亡嫌,就自動(dòng)發(fā)出一個(gè)"預(yù)檢"請(qǐng)求,要求服務(wù)器確認(rèn)可以這樣請(qǐng)求掘而。下面是這個(gè)"預(yù)檢"請(qǐng)求的HTTP頭信息昼伴。

OPTIONS /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Request-Method: PUTAccess-Control-Request-Headers: X-Custom-Header
Host: api.alice.comAccept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

"預(yù)檢"請(qǐng)求用的請(qǐng)求方法是OPTIONS,表示這個(gè)請(qǐng)求是用來(lái)詢問(wèn)的镣屹。頭信息里面署尤,關(guān)鍵字段是Origin,表示請(qǐng)求來(lái)自哪個(gè)源炮赦。

2.預(yù)檢請(qǐng)求的回應(yīng)
服務(wù)器收到"預(yù)檢"請(qǐng)求以后板驳,檢查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后伪窖,確認(rèn)允許跨源請(qǐng)求逸寓,就可以做出回應(yīng)。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

上面的HTTP回應(yīng)中覆山,關(guān)鍵的是Access-Control-Allow-Origin字段竹伸,表示http://api.bob.com可以請(qǐng)求數(shù)據(jù)。該字段也可以設(shè)為星號(hào)簇宽,表示同意任意跨源請(qǐng)求勋篓。

Access-Control-Allow-Origin: *

如果瀏覽器否定了"預(yù)檢"請(qǐng)求,會(huì)返回一個(gè)正常的HTTP回應(yīng)魏割,但是沒(méi)有任何CORS相關(guān)的頭信息字段譬嚣。這時(shí),瀏覽器就會(huì)認(rèn)定钞它,服務(wù)器不同意預(yù)檢請(qǐng)求拜银,因此觸發(fā)一個(gè)錯(cuò)誤殊鞭,被XMLHttpRequest對(duì)象的onerror回調(diào)函數(shù)捕獲∧嵬埃控制臺(tái)會(huì)打印出如下的報(bào)錯(cuò)信息操灿。

XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

3.瀏覽器的正常請(qǐng)求和回應(yīng)
一旦服務(wù)器通過(guò)了"預(yù)檢"請(qǐng)求,以后每次瀏覽器正常的CORS請(qǐng)求泵督,就都跟簡(jiǎn)單請(qǐng)求一樣牲尺,會(huì)有一個(gè)Origin頭信息字段。服務(wù)器的回應(yīng)幌蚊,也都會(huì)有一個(gè)Access-Control-Allow-Origin頭信息字段谤碳。
下面是"預(yù)檢"請(qǐng)求之后,瀏覽器的正常CORS請(qǐng)求溢豆。

PUT /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面頭信息的Origin字段是瀏覽器自動(dòng)添加的蜒简。
下面是服務(wù)器正常的回應(yīng)。

Access-Control-Allow-Origin: [http://api.bob.com](http://api.bob.com/)
Content-Type: text/html; charset=utf-8

上面頭信息中漩仙,Access-Control-Allow-Origin字段是每次回應(yīng)都必定包含的搓茬。

  • 與JSONP的比較
    CORS與JSONP的使用目的相同,但是比JSONP更強(qiáng)大队他。
    JSONP只支持GET請(qǐng)求卷仑,CORS支持所有類型的HTTP請(qǐng)求。JSONP的優(yōu)勢(shì)在于支持老式瀏覽器麸折,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)锡凝。

5.根據(jù)視頻里的講解演示三種以上跨域的解決方式
JSONP:

<!DOCTYPE html>
<html>
<head>
    <title>JSONP</title>
    <style type="text/css">
        ul,li{
            list-style: none;
        }
        li:hover{
            color: #fff;
            background-color: #6ff;
        }
        .news{
            margin: auto;
        }
        li{
            margin: 10px ;
        
        }
        .btn {
            outline: none;
            border: 1px solid #ddd;
            color: #000;
            background-color: #fff;
            border-radius: 3px;
            display: block;
            margin: 15px 50px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="ct">
        <ul class="news">
            <li>第11日前瞻,中國(guó)沖擊4金垢啼,博爾特再戰(zhàn)</li>
            <li>男雙力爭(zhēng)會(huì)師決賽</li>
            <li>女排將死磕巴西窜锯!</li>
        </ul>
        <button class="btn">換一組</button>
    </div>
    
    <script type="text/javascript">
        function $(e){
            return document.querySelector(e);
        }
        $('.btn').addEventListener('click',function(){
            var script = document.createElement('script')
            script.src = 'http://a.hgz.com:8080/getNews?callback=foo'
            document.head.appendChild(script)
            document.head.removeChild(script)
        })

        function foo(news){
            var html = ''
            for(var i =0; i<news.length;i++){
                html+= '<li>' + news[i] + '</li>'
            }
            $('.news').innerHTML = html
        }
    </script>
</body>
</html>

router.js

app.get('/getNews', function(req, res){
     var news = [
     "第11日前瞻,中國(guó)沖擊4金芭析,博爾特再戰(zhàn)",
     "男雙力爭(zhēng)會(huì)師決賽",
     "女排將死磕巴西锚扎!郎平安排男陪練模仿對(duì)方核心",
     "沒(méi)有中國(guó)選手和巨星的110米欄 我們還看嗎",
     "中英上演奧運(yùn)金牌大戰(zhàn)",
     "博彩賠率挺中國(guó)奪回第二紐約時(shí)報(bào):中國(guó)因?qū)κ址幎鴣G失的獎(jiǎng)牌最多",
     "[邊界] 最“出柜”奧運(yùn) 同性之愛閃耀里約",
     "[特評(píng)] 下跪拜謝與洪荒之力一樣 都是真情流露"
     ]

     var data = []
     for(var i = 0; i<3; i++){
        var index = parseInt(Math.random()*news.length);
        data.push(news[index])
        news.splice(index, 1)    //保證3條信息不重復(fù)
     }

     var cb = req.query.callback;    //必須重新聲明callback

     res.send(cb + '(' + JSON.stringify(data) + ')');    //生成foo(news)的形式的字符串
})

CORS
代碼與ajax幾乎一樣

<!DOCTYPE html>
<html>
<head>
    <title>JSONP</title>
    <style type="text/css">
        ul,li{
            list-style: none;
        }
        li:hover{
            color: #fff;
            background-color: #6ff;
        }
        .news{
            margin: auto;
        }
        li{
            margin: 10px ;
        
        }
        .btn {
            outline: none;
            border: 1px solid #ddd;
            color: #000;
            background-color: #fff;
            border-radius: 3px;
            display: block;
            margin: 15px 50px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="ct">
        <ul class="news">
            <li>第11日前瞻,中國(guó)沖擊4金馁启,博爾特再戰(zhàn)</li>
            <li>男雙力爭(zhēng)會(huì)師決賽</li>
            <li>女排將死磕巴西驾孔!</li>
        </ul>
        <button class="btn">換一組</button>
    </div>
    
    <script type="text/javascript">
        function $(e){
            return document.querySelector(e);
        }
        $('.btn').addEventListener('click',function(){
            var xhr = new XMLHttpRequest()
            xhr.open('get', 'http://hgz.com:8080/getNews', true)
            xhr.send()
            xhr.onreadystatechange = function(){
                if (xhr.readyState === 4){
                    if (xhr.status ===200 || xhr.status=== 304){
                        foo(JSON.parse(xhr.responseText))
                    }
                }
            }
            
        })
        function foo(news){
            var html = ''
            for(var i =0; i<news.length;i++){
                html+= '<li>' + news[i] + '</li>'
            }
            $('.news').innerHTML = html
        }
    </script>
</body>
</html>

router.js

app.get('/getNews', function(req, res){
     var news = [
     "第11日前瞻,中國(guó)沖擊4金惯疙,博爾特再戰(zhàn)",
     "男雙力爭(zhēng)會(huì)師決賽",
     "女排將死磕巴西翠勉!郎平安排男陪練模仿對(duì)方核心",
     "沒(méi)有中國(guó)選手和巨星的110米欄 我們還看嗎",
     "中英上演奧運(yùn)金牌大戰(zhàn)",
     "博彩賠率挺中國(guó)奪回第二紐約時(shí)報(bào):中國(guó)因?qū)κ址幎鴣G失的獎(jiǎng)牌最多",
     "[邊界] 最“出柜”奧運(yùn) 同性之愛閃耀里約",
     "[特評(píng)] 下跪拜謝與洪荒之力一樣 都是真情流露"
     ]

     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://hgz.com:8080")    //返回的res頭部加上Origin
     // res.header("Access-Control-Allow-Origin", "*")
     res.send(data);
})

演示

gif002.gif

降域
a.html

<!DOCTYPE html>
<html>

    <title></title>

<style type="text/css">
    .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>使用降域?qū)崿F(xiàn)跨域</h1>
        <div class="main">
            <input type="text" placeholder="http://a.hgz.com:8080/a.html">
        </div>
        <iframe src="http://a.hgz.com:8080/b.html" frameborder="0"></iframe>
    </div>
    <script type="text/javascript">
        //URL:http//a.hgz.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 = 'hgz.com'
    </script>
</html>

b.html

<!DOCTYPE html>
<html>

    <style type="text/css">
        html,body{
            margin: 0;
        }
        input{
            margin: 20px;
            width: 200px;
        }
    </style>
    <input id="input" type="text" placeholder="http://b.hgz.com:8080/b.html">
    <script>
        // URL:http://b.hgz.com:8080/b.html
        document.querySelector('#input').addEventListener('input',function(){
            window.parent.document.querySelector('input').value = this.value
        })

        document.domain = 'hgz.com';
    </script>

</html>

postMessage
a.html

<!DOCTYPE html>
<html>

    <title></title>

<style type="text/css">
    .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>使用降域?qū)崿F(xiàn)跨域</h1>
        <div class="main">
            <input type="text" placeholder="http://a.hgz.com:8080/a.html">
        </div>
        <iframe src="http://b.hgz.com:8080/b.html" frameborder="0"></iframe>
    </div>
    <script type="text/javascript">
        //URL:http//a.hgz.com:8080/a.html

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

         $('.main input').addEventListener('input', function(){
            console.log(this.value)
            window.frames[0].postMessage(this.value, '*')
         })    //左邊為消息,右邊同意任意跨源請(qǐng)求

         window.addEventListener('message', function(e){
            $('.main input').value = e.data
         })
        
    </script>
</html>

b.html

<!DOCTYPE html>
<html>

    <style type="text/css">
        html,body{
            margin: 0;
        }
        input{
            margin: 20px;
            width: 200px;
        }
    </style>
    <input id="input" type="text" placeholder="http://b.hgz.com:8080/b.html">
    <script>
        // URL:http://b.hgz.com:8080/b.html

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

         $('#input').addEventListener('input', function(){
            
            window.parent.postMessage(this.value, '*')
         })

         window.addEventListener('message', function(e){
            $('#input').value = e.data
            console.log(e.data)
         })
    </script>

</html>

演示

gif003.gif

文章摘錄自阮一峰的網(wǎng)絡(luò)日志瀏覽器同源政策及其規(guī)避方法跨域資源共享 CORS 詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末螟碎,一起剝皮案震驚了整個(gè)濱河市眉菱,隨后出現(xiàn)的幾起案子迹栓,更是在濱河造成了極大的恐慌掉分,老刑警劉巖俭缓,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異酥郭,居然都是意外死亡华坦,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門不从,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惜姐,“玉大人,你說(shuō)我怎么就攤上這事椿息〈踉” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵寝优,是天一觀的道長(zhǎng)条舔。 經(jīng)常有香客問(wèn)我,道長(zhǎng)乏矾,這世上最難降的妖魔是什么孟抗? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮钻心,結(jié)果婚禮上凄硼,老公的妹妹穿的比我還像新娘。我一直安慰自己捷沸,他們只是感情好摊沉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著痒给,像睡著了一般坯钦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上侈玄,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天婉刀,我揣著相機(jī)與錄音,去河邊找鬼序仙。 笑死突颊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潘悼。 我是一名探鬼主播律秃,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼治唤!你這毒婦竟也來(lái)了棒动?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤宾添,失蹤者是張志新(化名)和其女友劉穎船惨,沒(méi)想到半個(gè)月后柜裸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粱锐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年疙挺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怜浅。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铐然,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恶座,到底是詐尸還是另有隱情搀暑,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布跨琳,位于F島的核電站险掀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏湾宙。R本人自食惡果不足惜樟氢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望侠鳄。 院中可真熱鬧埠啃,春花似錦、人聲如沸伟恶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)博秫。三九已至潦牛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挡育,已是汗流浹背巴碗。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留即寒,地道東北人橡淆。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像母赵,于是被迫代替她去往敵國(guó)和親逸爵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 題目1: 什么是同源策略由于瀏覽器的安全設(shè)置凹嘲,在利用AJAX進(jìn)行通信時(shí)师倔,默認(rèn)情況下,XHR對(duì)象只能訪問(wèn)與包含它的頁(yè)...
    饑人谷_桶飯閱讀 241評(píng)論 0 0
  • 什么是同源策略 同源政策(same-origin policy)是指同域名(或ip),同端口周蹭,同協(xié)議視為同一個(gè)域趋艘,...
    小囧兔閱讀 513評(píng)論 0 1
  • 1- 同源策略: 首先理解什么叫同源同源指的是協(xié)議疲恢、域名、端口都必須一致致稀。只要其中一個(gè)不一致都不是同源冈闭。 瀏覽器中...
    osborne閱讀 177評(píng)論 0 1
  • 歡迎關(guān)注微信公眾號(hào):全棧工廠 本文主要參考跨域資源共享 CORS 詳解[http://www.ruanyifeng...
    liqingbiubiu閱讀 1,846評(píng)論 0 3
  • 你應(yīng)該知道的那些Android小經(jīng)驗(yàn) 1.枚舉提供類型安全 Android代碼替代枚舉的正確之道 2.匿名toke...
    gadfly_only閱讀 675評(píng)論 1 50