1. 什么是同源策略
瀏覽器限制不同源的兩個(gè)網(wǎng)站間腳本和文本的相互訪問(wèn),只允許訪問(wèn)同源下的內(nèi)容。所謂同源,就是指兩個(gè)頁(yè)面具有相同的協(xié)議,主機(jī)(也常說(shuō)域名),端口,三個(gè)要素缺一不可。同源政策的目的,是為了保證用戶信息的安全,防止惡意的網(wǎng)站竊取數(shù)據(jù)。
2. 什么是跨域?跨域有幾種實(shí)現(xiàn)形式
- 關(guān)于跨域
說(shuō)白點(diǎn)就是post、get的url不是你當(dāng)前的網(wǎng)站,域名不同。例如在aaa.com/a.html里面,表單的提交action是bbb.com/b.html。
不僅如此www.aaa.com和aaa.com之間也屬于跨域,因?yàn)?a target="_blank" rel="nofollow">www.aaa.com是二級(jí)域名,aaa.com是根域名。
JavaScript出于安全方面的考慮,是不允許跨域調(diào)用其他頁(yè)面的對(duì)象的
[圖片上傳失敗...(image-b1caef-1514307447090)]
[圖片上傳失敗...(image-50a6ca-1514307447091)] - 關(guān)于跨域的原因
跨域這東西其實(shí)很常見(jiàn),例如我們可以把網(wǎng)站的一些腳本、圖片或其他資源放到另外一個(gè)站點(diǎn)。例如我們可以使用Google提供的jQuery,加載時(shí)間少了,而且減少了服務(wù)器的流量,如下
<script type="text/java script"src="https://aja x.googleapis.com/aj ax/libs/jquery/1.4.2/jquery.min.js"></script>
有時(shí)候不僅僅是一些腳本、圖片這樣的資源,我們也會(huì)希望從另外的站點(diǎn)調(diào)用一些數(shù)據(jù)(有時(shí)候是不得不這樣),例如我希望獲取一些blog的RSS來(lái)生成一些內(nèi)容,再或者說(shuō)我在“人人開(kāi)放平臺(tái)”上開(kāi)發(fā)一個(gè)應(yīng)用,需要調(diào)用人人的數(shù)據(jù)。
然而,很不幸的是,直接用XMLHttpRequest來(lái)Get或者Post是不行的。
- 跨域的實(shí)現(xiàn)方式
- 在服務(wù)器端進(jìn)行通信,因?yàn)榉?wù)器端不受跨域的限制??缬虻陌踩拗剖菍?duì)瀏覽器端來(lái)說(shuō)的。
- 用 script 標(biāo)簽來(lái)解決,因?yàn)樗?src 屬性是可以跨域的。
eg. 往常用 script 引入外部的 js
eg. 也可以用 js 動(dòng)態(tài)創(chuàng)建 script 標(biāo)簽,并將其 append 到 body 里,就可以用這個(gè) js 了。- jsonp:它其實(shí)是一個(gè)非官方的協(xié)議,有特定的通信邏輯,但平時(shí)原生用的不多,因?yàn)?jQuery 本身就支持了 jsonp。
-
$.ajax(),$.getJSON():jQuery提供的現(xiàn)成函數(shù)來(lái)實(shí)現(xiàn)跨域。這兩種方式(其實(shí)就是一種調(diào)用方式,需要傳特定的參數(shù))的原理是將 json 數(shù)據(jù)填充進(jìn)回調(diào)函數(shù),即創(chuàng)建一個(gè)回調(diào)函數(shù),在遠(yuǎn)程服務(wù)器上調(diào)用這個(gè)函數(shù)并將 json 數(shù)據(jù)形式作為參數(shù),完成回調(diào)。 - iFrame 實(shí)現(xiàn)跨域
- HTML5 的 postMessage 和 onmessage
其實(shí) jsonp 里面也是創(chuàng)建了 script 標(biāo)簽,然后通過(guò) js 回調(diào)的形式實(shí)現(xiàn)了跨域訪問(wèn)。而 jQuery 對(duì) jsonp 也僅僅是支持,其核心也是 jsonp。所以,歸根結(jié)底,這三種方式都是常見(jiàn)又經(jīng)常被忽略的 script 標(biāo)簽。
3. JSONP 的原理是什么
jsonp是一種跨域通信的手段,它的原理其實(shí)很簡(jiǎn)單:
首先是利用script標(biāo)簽的src屬性來(lái)實(shí)現(xiàn)跨域。
通過(guò)將前端方法作為參數(shù)傳遞到服務(wù)器端,然后由服務(wù)器端注入?yún)?shù)之后再返回,實(shí)現(xiàn)服務(wù)器端向客戶端通信。
由于使用script標(biāo)簽的src屬性,因此只支持get方法
4. CORS是什么
CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 ajax 跨域請(qǐng)求資源的方式,支持現(xiàn)代瀏覽器,IE支持10以上。 實(shí)現(xiàn)方式很簡(jiǎn)單,當(dāng)你使用 XMLHttpRequest 發(fā)送請(qǐng)求時(shí),瀏覽器發(fā)現(xiàn)該請(qǐng)求不符合同源策略,會(huì)給該請(qǐng)求加一個(gè)請(qǐng)求頭:Origin,后臺(tái)進(jìn)行一系列處理,如果確定接受請(qǐng)求則在返回結(jié)果中加入一個(gè)響應(yīng)頭:Access-Control-Allow-Origin; 瀏覽器判斷該相應(yīng)頭中是否包含 Origin 的值,如果有則瀏覽器會(huì)處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù),如果不包含瀏覽器直接駁回,這時(shí)我們無(wú)法拿到響應(yīng)數(shù)據(jù)。所以 CORS 的表象是讓你覺(jué)得它與同源的 ajax 請(qǐng)求沒(méi)啥區(qū)別,代碼完全一樣。
整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺(jué)。
實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。
瀏覽器將CORS請(qǐng)求分為兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求
5. 演示三種以上跨域的解決方式
1.JSONP實(shí)現(xiàn)跨域
Web 頁(yè)面上調(diào)用 js 文件不受瀏覽器同源策略的影響,所以通過(guò) Script 便簽可以進(jìn)行跨域的請(qǐng)求:
- 首先前端先設(shè)置好回調(diào)函數(shù),并將其作為 url 的參數(shù)。
- 服務(wù)端接收到請(qǐng)求后,通過(guò)該參數(shù)獲得回調(diào)函數(shù)名,并將數(shù)據(jù)放在參數(shù)中將其返回
- 收到結(jié)果后因?yàn)槭?script 標(biāo)簽,所以瀏覽器會(huì)當(dāng)做是腳本進(jìn)行運(yùn)行,從而達(dá)到跨域獲取數(shù)據(jù)的目的。
實(shí)例演示:
后端邏輯:文件名server.js
//后端邏輯
var url = require('url')
var http = require('http')
http.createServer(function (req, res) {
var data = {
name: "haha"
};
var callback = url.parse(req.url,true).query.callback;
//url.parse(req.url,true).query即{callback:jsonpCallback} ----------------獲取函數(shù)名callback
res.writeHead(200)
res.end(`${callback}(${JSON.stringify(data)})`)
}).listen(3000, '127.0.0.1')
//服務(wù)端接收到請(qǐng)求后獲取到回調(diào)函數(shù)名callback,
將數(shù)據(jù)放在參數(shù)中將其返回,即返回callback({"name" : "haha"}) 函數(shù)調(diào)用
console.log('監(jiān)聽(tīng)127.0.0.1:3000端口')
//注意這里文字一定要引號(hào)包裹不然會(huì)報(bào)錯(cuò)
//注意終端提示:SyntaxError: Invalid or unexpected token 無(wú)效或意外的標(biāo)記,
出現(xiàn)這種情況一般是中文的標(biāo)點(diǎn)符號(hào)或者漏寫了符號(hào)導(dǎo)致的
前端頁(yè)面:文件名index.html
<!--前端頁(yè)面-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONP實(shí)現(xiàn)跨域</title>
</head>
<body>
<script>
function jsonpCallback(data) {
console.log(JSON.stringfy(data))
}
//定義回調(diào)函數(shù)jsonpCallback,收到服務(wù)端返回結(jié)果
callback({"name" : "haha"}),callback=jsonpCallback
</script>
<script src="http://127.0.0.1:3000?callback=jsonpCallback"></script>
//web頁(yè)面上調(diào)用js文件不收同源策略影響
</body>
</html>
驗(yàn)證過(guò)程:
-
終端在后端文件server.js目錄下,node server.js啟動(dòng)服務(wù),監(jiān)聽(tīng)端口3000
-
我們通過(guò)端口號(hào)的不同來(lái)模擬跨域的場(chǎng)景,通過(guò)127.0.0.1:8080端口來(lái)訪問(wèn)頁(yè)面.
這里我們打開(kāi)另一個(gè)終端,在頁(yè)面同目錄下輸入http-server啟動(dòng)端口
這樣就可以通過(guò)端口 8080 訪問(wèn) index.html 剛才那個(gè)頁(yè)面了,相當(dāng)于是開(kāi)啟兩個(gè)監(jiān)聽(tīng)不同端口的 http 服務(wù)器,通過(guò)頁(yè)面中的請(qǐng)求來(lái)模擬跨域的場(chǎng)景。打開(kāi)瀏覽器,訪問(wèn) http://127.0.0.1:8080就可以看到從http://127.0.0.1:3000獲取到的數(shù)據(jù)了。
至此,通過(guò) JSONP 跨域獲取數(shù)據(jù)已經(jīng)成功了,但是通過(guò)這種事方式也存在著一定的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1.它不像XMLHttpRequest 對(duì)象實(shí)現(xiàn) Ajax 請(qǐng)求那樣受到同源策略的限制
2.兼容性很好,在古老的瀏覽器也能很好的運(yùn)行
3.不需要 XMLHttpRequest 或 ActiveX 的支持;并且在請(qǐng)求完畢后可以通過(guò)調(diào)用 callback 的方式回傳結(jié)果。
缺點(diǎn):
1.它支持 GET 請(qǐng)求而不支持 POST 等其它類型的 HTTP 請(qǐng)求。
2.它只支持跨域 HTTP 請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁(yè)面或 iframe 之間進(jìn)行數(shù)據(jù)通信的問(wèn)題
3.容易遭受XSS攻擊,因?yàn)槲覀兡玫降氖菍?duì)方接口的數(shù)據(jù)作為js執(zhí)行,如果得到的是一個(gè)很危險(xiǎn)js,獲取了用戶信息和cookies,這時(shí)執(zhí)行了js就會(huì)出現(xiàn)安全問(wèn)題。
2. CORS實(shí)現(xiàn)跨域
CORS 是一個(gè) W3C 標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)它允許瀏覽器向跨源服務(wù)器,發(fā)出 XMLHttpRequest 請(qǐng)求,從而克服了 ajax 只能同源使用的限制。
CORS 需要瀏覽器和服務(wù)器同時(shí)支持才可以生效,對(duì)于開(kāi)發(fā)者來(lái)說(shuō),CORS 通信與同源的 ajax 通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn) ajax 請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺(jué)。參考阮一峰
因此,實(shí)現(xiàn) CORS 通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了 CORS 接口,就可以跨源通信。
<!--前端頁(yè)面-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://127.0.0.1:3000', true)
xhr.send()
xhr.onload = function () {
console.log(xhr.responseText)
}
</script>
</body>
</html>
這似乎跟一次正常的異步 ajax 請(qǐng)求沒(méi)有什么區(qū)別,關(guān)鍵是在服務(wù)端收到請(qǐng)求后的處理:
var http = require('http')
http.createServer(function(req,res){
res.writeHead(200,{
'Acess-Control-Allow-Origin':'http://127.0.0.1:8080'
})
res.end('這是你要的數(shù)據(jù): haha')
}).listen(3000,'127.0.0.1')
console.log('監(jiān)聽(tīng)127.0.0.1:3000端口')
關(guān)鍵是在于設(shè)置相應(yīng)頭中的 Access-Control-Allow-Origin,該值要與請(qǐng)求頭中 Origin 一致才能生效,否則將跨域失敗。
開(kāi)啟兩個(gè)http服務(wù)器

打開(kāi)瀏覽器訪問(wèn)localhost:8080,

成功的關(guān)鍵在于 Access-Control-Allow-Origin是否包含請(qǐng)求頁(yè)面的域名,如果不包含的話,瀏覽器認(rèn)為是跨域請(qǐng)求,會(huì)攔截返回的信息.
另外如果服務(wù)器設(shè)置:
res.writeHead(200,{
'Acess-Control-Allow-Origin': * //開(kāi)放接口,任何人都能跨域調(diào)用該接口內(nèi)的數(shù)據(jù)
})
CORS 的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
- 使用簡(jiǎn)單方便,更為安全
- 支持 POST 請(qǐng)求方式
- 精確控制資源訪問(wèn)權(quán)限
- 客戶端無(wú)需增加額外代碼
缺點(diǎn):
1. CORS僅兼容 IE 10 以上
3.Server Proxy服務(wù)器代理
需要跨域的請(qǐng)求操作時(shí)發(fā)送請(qǐng)求給后端,讓后端幫你代為請(qǐng)求,然后將獲取的結(jié)果發(fā)送給你。
假設(shè)你的頁(yè)面需要獲取 CNode:Node.js專業(yè)中文社區(qū) 論壇上一些數(shù)據(jù),如通過(guò) https://cnodejs.org/api/v1/topics,因?yàn)椴煌?,所以你可以?qǐng)求后端讓其代為轉(zhuǎn)發(fā)請(qǐng)求。
var url = require('url');
var http = require('http');
var https = require('https');
var server = http.createServer((req, res) => { // =>前面是參數(shù),后面是函數(shù)體
var path = url.parse(req.url).path.slice(1);
if(path === 'topics'){
https.get('https://cnodejs.org/api/v1/topics',(resp) => {
var data = "";
resp.on('data',chunk => {
data += chunk;
})
resp.on('end', () => {
res.writeHead(200, {
'Content-Type': 'application/json; charset=utf-8'
});
res.end(data);
})
})
}
}).listen(3000,'127.0.0.1');
console.log('啟動(dòng)服務(wù),監(jiān)聽(tīng) 127.0.0.1:3000');
開(kāi)啟服務(wù)器:

打開(kāi)瀏覽器訪問(wèn)http://localhost:3000/topics就可以看到:

獲取到數(shù)據(jù),跨域成功
總結(jié)
四種iframe跨域
1.postMessage實(shí)現(xiàn)跨域
postMessage 是 HTML5 新增加的一項(xiàng)功能,跨文檔消息傳輸(Cross Document Messaging),目前:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持這項(xiàng)功能,使用起來(lái)也特別簡(jiǎn)單。
首先創(chuàng)建 a.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>a.html</title>
</head>
<body>
<iframe src="http://localhost:8081/b.html" style='display: none;'></iframe>
<script>
window.onload = function(){
var targetOrigin = 'http://localhost:8081';
window.frames[0].postMessage('看到我發(fā)給你的信息沒(méi)',targetOrigin) //window.frames[0]是內(nèi)嵌的窗口
}
window.addEventListener('message',function(e){
console.log('a.html接收到信息:',e.data)
});
</script>
</body>
</html>
創(chuàng)建內(nèi)嵌b.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>b.html</title>
</head>
<body>
<script>
window.addEventListener('message',function(e){
if(e.source != window.parent){
return;
}
var data = e.data;
console.log('b.html 接收到的消息:', data);
parent.postMessage('我看到你發(fā)的消息了!',e.origin)
})
</script>
</body>
</html>
然后同時(shí)開(kāi)啟服務(wù)器:注意b.html服務(wù)器開(kāi)啟更改接口命令:http-server -p 8081

在瀏覽器中打開(kāi)http://127.0.0.1:8080/a.html

跨域成功.
參考教程:Window.postMessage()
2.document.domain實(shí)現(xiàn)跨域:(降域)
對(duì)于主域相同而子域不同的情況下,可以通過(guò)設(shè)置 document.domain 的辦法來(lái)解決,具體做法是可以在 http://www.example.com/a.html和http://sub.example.com/b.html兩個(gè)文件分別加上 document.domain = "a.com";然后通過(guò) a.html 文件創(chuàng)建一個(gè) iframe,去控制 iframe 的 window,從而進(jìn)行交互,當(dāng)然這種方法只能解決主域相同而二級(jí)域名不同的情況
測(cè)試的方式稍微復(fù)雜點(diǎn),需要安裝 nginx 做域名映射,如果你電腦沒(méi)有安裝 nginx,請(qǐng)先去安裝一下: nginx news
安裝教程:https://www.cnblogs.com/chuncn/archive/2011/10/14/2212291.html
先創(chuàng)建一個(gè) a.html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>a.html</title>
</head>
<body>
<script>
document.domain = 'example.com' //a,b分別加上 document.domain = "example.com"
var ifr = document.createElement('iframe'); //創(chuàng)建一個(gè)iframe 內(nèi)嵌窗
ifr.src = 'http://sub.example.com/b.html';
ifr.style.display = 'none';
document.body.append(ifr)
ifr.onload = function(){
var win = ifr.contentWindow; //控制內(nèi)嵌iframe的窗口信息
alert(win.data)
}
</script>
</body>
</html>
創(chuàng)建b.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>b.html</title>
</head>
<body>
<script>
document.domain = 'example.com';
window.data = '傳送的數(shù)據(jù):1111';
</script>
</body>
</html>
開(kāi)啟服務(wù)器

這時(shí)候只是開(kāi)啟了兩個(gè) http 服務(wù)器,還需要通過(guò) nginx 做域名映射,將 Example Domain映射到 localhost:8080,sub.example.com 映射到localhost:8081上打開(kāi)操作系統(tǒng)下的 hosts 文件:mac 是位于 /etc/hosts 文件,并添加:
127.0.0.1 www.example.com
127.0.0.1 sub.example.com
windows修改host參考:
http://chongzhuang.windowszj.com/faq/164.html
修改好后保存,這樣在瀏覽器打開(kāi)兩個(gè)網(wǎng)址后就會(huì)訪問(wèn)本地的服務(wù)器.
之后打開(kāi) nginx 的配置文件:/usr/local/etc/nginx/nginx.conf,并在 http 模塊里添加:
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://127.0.0.1:8080/;
}
}
server {
listen 80;
server_name sub.example.com;
location / {
proxy_pass http://127.0.0.1:8081/;
}
}
如果訪問(wèn)本地的域名是www.example.com,就由 localhost:8080 代理該請(qǐng)求。所以我們這時(shí)候在打開(kāi)瀏覽器訪問(wèn)www.example.com的時(shí)候其實(shí)訪問(wèn)的就是本地服務(wù)器 localhost:8080。
3.location.hash實(shí)現(xiàn)跨域
在 url 中,http://www.baidu.com#helloworld的#helloworld 就是 location.hash,改變 hash 值不會(huì)導(dǎo)致頁(yè)面刷新,所以可以利用 hash 值來(lái)進(jìn)行數(shù)據(jù)的傳遞,當(dāng)然數(shù)據(jù)量是有限的。
假設(shè)localhost:8080下有文件 cs1.html要和 localhost:8081 下的 cs2.html傳遞消息,cs1.html首先創(chuàng)建一個(gè)隱藏的iframe,iframe 的 src指向 localhost:8081/cs2.html,這時(shí)的 hash 值就可以做參數(shù)傳遞。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CS1</title>
</head>
<body>
<script>
// http://localhost:8080/cs1.html
let ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = "http://localhost:8081/cs2.html#data";
document.body.appendChild(ifr);
function checkHash() {
try {
let data = location.hash ? location.hash.substring(1) : '';
console.log('獲得到的數(shù)據(jù)是:', data);
}catch(e) {
}
}
window.addEventListener('hashchange', function(e) {
console.log('獲得的數(shù)據(jù)是:', location.hash.substring(1));
});
</script>
</body>
</html>
cs2.html 收到消息后通過(guò) parent.location.hash 值來(lái)修改 cs1.html 的 hash 值,從而達(dá)到數(shù)據(jù)傳遞。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CS2</title>
</head>
<body>
<script>
// http://locahost:8081/cs2.html
switch(location.hash) {
case "#data":
callback();
break;
}
function callback() {
const data = "some number: 1111"
try {
parent.location.hash = data;
}catch(e) {
// ie, chrome 下的安全機(jī)制無(wú)法修改 parent.location.hash
// 所以要利用一個(gè)中間的代理 iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://localhost:8080/cs3.html#' + data; // 該文件在請(qǐng)求域名的域下
document.body.appendChild(ifrproxy);
}
}
</script>
</body>
</html>
作者:FLYSASA
鏈接:http://www.itdecent.cn/p/211cace53f04
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CS2</title>
</head>
<body>
<script>
// http://locahost:8081/cs2.html
switch(location.hash) {
case "#data":
callback();
break;
}
function callback() {
const data = "some number: 1111"
try {
parent.location.hash = data;
}catch(e) {
// ie, chrome 下的安全機(jī)制無(wú)法修改 parent.location.hash
// 所以要利用一個(gè)中間的代理 iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://localhost:8080/cs3.html#' + data; // 該文件在請(qǐng)求域名的域下
document.body.appendChild(ifrproxy);
}
}
</script>
</body>
</html>
由于兩個(gè)頁(yè)面不在同一個(gè)域下IE、Chrome不允許修改parent.location.hash的值,所以要借助于 localhost:8080 域名下的一個(gè)代理 iframe 的 cs3.html 頁(yè)面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cs3</title>
</head>
<body>
<script>
parent.parent.location.hash = self.location.hash.substring(1);
</script>
</body>
</html>
同樣開(kāi)啟服務(wù)器

這里為了圖方便,將 cs1,2,3 都放在同個(gè)文件夾下,實(shí)際情況的話 cs1.html 和 cs3.html 要與 cs2.html 分別放在不同的服務(wù)器才對(duì)。
之后打開(kāi)瀏覽器訪問(wèn) localhost:8080/cs1.html,注意不是 8081,就可以看到獲取到的數(shù)據(jù)了,此時(shí)頁(yè)面的 hash 值也已經(jīng)改變。

缺點(diǎn):
- 數(shù)據(jù)直接暴露在了 url 中
- 數(shù)據(jù)容量和類型都有限
4.window.name實(shí)現(xiàn)跨域
window.name(一般在 js 代碼里出現(xiàn))的值不是一個(gè)普通的全局變量,而是當(dāng)前窗口的名字,這里要注意的是每個(gè) iframe 都有包裹它的window,而這個(gè) window 是top window 的子窗口,而它自然也有 window.name 的屬性,window.name 屬性的神奇之處在于 name 值在不同的頁(yè)面(甚至不同域名)加載后依舊存在(如果沒(méi)修改則值不會(huì)變化),并且可以支持非常長(zhǎng)的 name 值(2MB)。
舉個(gè)簡(jiǎn)單的例子:
你在某個(gè)頁(yè)面的控制臺(tái)輸入:
window.name = "Hello World";
window.location = "http://www.baidu.com";
頁(yè)面跳轉(zhuǎn)到了百度首頁(yè),但是window.name卻被保存了下來(lái),還是 Hello World,跨域解決方案似乎可以呼之欲出了:
頁(yè)面跳轉(zhuǎn)到了百度首頁(yè),但是window.name卻被保存了下來(lái),還是 Hello World,跨域解決方案似乎可以呼之欲出了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>a.html</title>
</head>
<body>
<script>
var data = '';
const ifr = document.createElement('iframe');
ifr.src = "http://localhost:8081/b.html";
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function() {
ifr.onload = function() {
data = ifr.contentWindow.name;
console.log('收到數(shù)據(jù):', data);
}
ifr.src = "about:blank";
}
</script>
</body>
</html>
再創(chuàng)建b文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>b.html</title>
</head>
<body>
<script>
window.name = "你想要的數(shù)據(jù)!";
</script>
</body>
</html>
http://localhost:8080/a.html在請(qǐng)求遠(yuǎn)端服務(wù)器http://localhost:8081/b.html的數(shù)據(jù),我們可以在該頁(yè)面下新建一個(gè) iframe,該iframe 的 src 屬性指向服務(wù)器地址(利用 iframe 標(biāo)簽的跨域能力),服務(wù)器文件 b.html 設(shè)置好 window.name 的值。
但是由于 a.html頁(yè)面和該頁(yè)面iframe 的 src 如果不同源的話,則無(wú)法操作iframe里的任何東西,所以就取不到 iframe 的 name值,所以我們需要在b.html加載完后重新?lián)Q個(gè)src設(shè)置成'about:blank;' ,如果不重新指向 src的話直接獲取 window.name 的話會(huì)獲取不到數(shù)據(jù).
在a.html中重新設(shè)置ifr.src = "about:blank";后,打開(kāi)兩個(gè)http服務(wù)器,訪問(wèn)http://127.0.0.1:8080/a.html



