一酪术、跨域and同源政策
1.跨域惩妇,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本普筹。它是由瀏覽器的同源策略造成的恤磷,是瀏覽器對(duì)javascript施加的安全限制面哼。
2.同源政策
- 協(xié)議相同
- 域名相同
- 端口相同
如:
如,http://www.example.com/dir/page.html
這個(gè)網(wǎng)址扫步,協(xié)議是http://
魔策,域名是www.example.com
,端口是80
(默認(rèn)端口可以省略)河胎。它的同源情況如下闯袒。
http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
https://www.example.com/dir/page.html:不同源(協(xié)議不同)
如果非同源,共有三種行為受到限制游岳。
(1) Cookie政敢、LocalStorage 和 IndexedDB 無法讀取。
(2) DOM 無法獲得胚迫。
(3) AJAX 請(qǐng)求無效(可以發(fā)送喷户,但瀏覽器會(huì)拒絕接受響應(yīng))。
二访锻、如何解決跨域問題
1.cookie
舉例來說褪尝,A網(wǎng)頁(yè)是http://w1.example.com/a.html
,B網(wǎng)頁(yè)是http://w2.example.com/b.html
期犬,那么只要設(shè)置相同的document.domain河哑,兩個(gè)網(wǎng)頁(yè)就可以共享Cookie。
document.domain = 'example.com';
這種方法只適用于 Cookie 和 iframe窗口龟虎,LocalStorage 和 IndexedDB 無法通過這種方法璃谨,規(guī)避同源政策,而要使用PostMessage API鲤妥。
2. frame
如果兩個(gè)窗口一級(jí)域名相同佳吞,只是二級(jí)域名不同,那么設(shè)置document.domain屬性旭斥,就可以規(guī)避同源政策容达,拿到DOM古涧。
對(duì)于完全不同源的網(wǎng)站,目前有兩種方法,可以解決跨域窗口的通信問題捕透。
- 片段識(shí)別符(fragment identifier)
URL的#號(hào)后面的部分,比如http://example.com/x.html#fragment
的#fragment
算芯。如果只是改變片段標(biāo)識(shí)符,頁(yè)面不會(huì)重新刷新凳宙。
父窗口可以把信息熙揍,寫入子窗口的片段標(biāo)識(shí)符。
子窗口通過監(jiān)聽hashchange事件得到通知氏涩。
子窗口也可以改變父窗口的片段標(biāo)識(shí)符届囚。 - 跨文檔通信API(Cross-document messaging)
window.postMessage
父窗口aaa.com
向子窗口bbb.com
發(fā)消息,調(diào)用postMessage是尖。
var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', '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');
- message事件的事件對(duì)象event,提供以下三個(gè)屬性逸吵。
event.source:發(fā)送消息的窗口
event.origin: 消息發(fā)向的網(wǎng)址
event.data: 消息內(nèi)容
window.addEventListener('message', receiveMessage);
function receiveMessage(event) {
event.source.postMessage('Nice to see you!', '*');
}
3.LocalStorage
通過window.postMessage凶硅,讀寫其他窗口的 LocalStorage 也成為了可能。
3.AJAX
同源政策規(guī)定扫皱,AJAX請(qǐng)求只能發(fā)給同源的網(wǎng)址咏尝,否則就報(bào)錯(cuò)。
除了架設(shè)服務(wù)器代理(瀏覽器請(qǐng)求同源服務(wù)器啸罢,再由后者請(qǐng)求外部服務(wù))编检,有三種方法規(guī)避這個(gè)限制。
- JSONP
- WebSocket
- CORS
(1)JSONP是服務(wù)器與客戶端跨源通信的常用方法扰才。最大特點(diǎn)就是簡(jiǎn)單適用允懂,老式瀏覽器全部支持,服務(wù)器改造非常小衩匣。
它的基本思想是蕾总,網(wǎng)頁(yè)通過添加一個(gè)<script>元素,向服務(wù)器請(qǐng)求JSON數(shù)據(jù)琅捏,這種做法不受同源政策限制生百;服務(wù)器收到請(qǐng)求后,將數(shù)據(jù)放在一個(gè)指定名字的回調(diào)函數(shù)里傳回來柄延。
//網(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);
}
//向服務(wù)器example.com發(fā)出請(qǐng)求
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
//該請(qǐng)求的查詢字符串有一個(gè)callback參數(shù),用來指定回調(diào)函數(shù)的名字市俊,這對(duì)于JSONP是必需的杨凑。
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
//服務(wù)器收到這個(gè)請(qǐng)求以后,會(huì)將數(shù)據(jù)放在回調(diào)函數(shù)的參數(shù)位置返回摆昧。
foo({
"ip": "8.8.8.8"
});
(2)WebSocket是一種通信協(xié)議撩满,使用ws://(非加密)和wss://(加密)作為協(xié)議前綴。該協(xié)議不實(shí)行同源政策绅你,只要服務(wù)器支持伺帘,就可以通過它進(jìn)行跨源通信。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
有一個(gè)字段是Origin忌锯,表示該請(qǐng)求的請(qǐng)求源(origin)曼追,即發(fā)自哪個(gè)域名。
正是因?yàn)橛辛薕rigin這個(gè)字段汉规,所以WebSocket才沒有實(shí)行同源政策礼殊。因?yàn)榉?wù)器可以根據(jù)這個(gè)字段,判斷是否許可本次通信针史。
(3)CORS
跨源資源分享(Cross-Origin Resource Sharing)晶伦。相比JSONP只能發(fā)GET請(qǐng)求,CORS允許任何類型的請(qǐng)求啄枕。
允許瀏覽器向跨源服務(wù)器婚陪,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制频祝。泌参。
CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前常空,所有瀏覽器都支持該功能沽一,IE瀏覽器不能低于IE10。
整個(gè)CORS通信過程漓糙,都是瀏覽器自動(dòng)完成
兩種請(qǐng)求
簡(jiǎn)單請(qǐng)求(simple request)
請(qǐng)求方法
HEAD
GET
POST
//HTTP頭信息
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded铣缠、
multipart/form-data、text/plain
非簡(jiǎn)單請(qǐng)求(not-so-simple request)
請(qǐng)求方法
PUT
DELETE
或者Content-Type字段的類型是application/json
昆禽。
- CORS與JSONP的使用目的相同蝗蛙,但是比JSONP更強(qiáng)大。
JSONP只支持GET請(qǐng)求醉鳖,CORS支持所有類型的HTTP請(qǐng)求捡硅。JSONP的優(yōu)勢(shì)在于支持老式瀏覽器,以及可以向不支持CORS的網(wǎng)站請(qǐng)求數(shù)據(jù)盗棵。