近期在重新看《JavaScript高級(jí)程序設(shè)計(jì)》記錄記錄每天新看的東西,做個(gè)小總結(jié)渗柿。
CORS
通過(guò) XHR 實(shí)現(xiàn) Ajax 通信的一個(gè)主要限制个盆,來(lái)源于跨域安全策略。默認(rèn)情況下 XHR 對(duì)象只能訪問(wèn)與包含它的頁(yè)面位于同一域中的資源颊亮。這種安全策略可以預(yù)防某些惡意行為终惑。
CORS(Cross-Origin Resource Sharing,跨源資源共享)是 W3C 的一個(gè)工作草案悯嗓,定義了必須訪問(wèn)跨域資源時(shí)件舵,瀏覽器與服務(wù)器之前應(yīng)該如何溝通(使用自定義的 HTTP 頭部讓瀏覽器和服務(wù)器進(jìn)行溝通,從而決定請(qǐng)求或響應(yīng)是應(yīng)該成功合武,還是應(yīng)該失斄俟!)。
簡(jiǎn)單的使用 GET 或 POST 發(fā)送請(qǐng)求時(shí)稼跳,給請(qǐng)求添加一個(gè)額外的 Origin 頭部盟庞,其中包含請(qǐng)求頁(yè)面的源信息(協(xié)議、域名和端口)汤善,以便服務(wù)器根據(jù)這個(gè)頭來(lái)決定是否給予響應(yīng)什猖。
如果服務(wù)器認(rèn)為這個(gè)請(qǐng)求可以接受,就在 Access-Control-Allow-Origin
頭部中回發(fā)相同的源信息(如果是公共資源红淡,可以回發(fā)'*')不狮。
請(qǐng)求和響應(yīng)都不包含 cookie 信息。
CORS的實(shí)現(xiàn):
-
IE
XDR(XDomainRequest)對(duì)象在旱。
與XHR類似但具有以下區(qū)別:Cookie 不能隨請(qǐng)求發(fā)送摇零,也不能隨響應(yīng)返回
不能訪問(wèn)響應(yīng)頭部信息
只能設(shè)置請(qǐng)求頭部信息中的 Content-Type 字段,用來(lái)表示發(fā)送數(shù)據(jù)的格式(POST數(shù)據(jù)的時(shí)候)
只支持 GET 和 POST 請(qǐng)求
只能通過(guò) load 事件監(jiān)聽(tīng)請(qǐng)求得到響應(yīng)(XHR可以監(jiān)聽(tīng) readystatechange 事件和 readyState 確定)
只能創(chuàng)建異步的CORS請(qǐng)求
-
不能訪問(wèn) status桶蝎,statusText 屬性
var xdr = new XDomainRequest(); xdr.onload = function() { alert(xdr.responseText); // 響應(yīng)信息保存在 responseText 屬性中 } // xdr 只能創(chuàng)建 異步的請(qǐng)求驻仅,也沒(méi)有辦法創(chuàng)建同步請(qǐng)求 xdr.open('get', 'http://www.some-other.com/index.php'); xdr.send(null);
-
其他現(xiàn)代瀏覽器
FireFox 3.5+、Safari 4+登渣、Chrome噪服、IOS 版 Safari 和 Android 平臺(tái)中的 WebKit 都是通過(guò) XMLHttpRequest 對(duì)象實(shí)現(xiàn)了對(duì) CORS 的原生支持。當(dāng)嘗試打開(kāi)來(lái)自不同源的資源時(shí)绍豁,無(wú)需額外代碼芯咧,只需將 open 方法中傳入的 URL 設(shè)置為絕對(duì) URL 即可。
用于實(shí)現(xiàn) CORS 的 XHR 對(duì)象和完成 Ajax 的 XHR 對(duì)象對(duì)比的一些限制:
- 不能使用 setRequestHeader() 設(shè)置自定義頭部
- 不能發(fā)送和接受 cookie
- 調(diào)用 getAllResponseHeaders() 方法總是返回空字符串
由于無(wú)論是同源請(qǐng)求還是跨域請(qǐng)求都使用相同的接口,因此對(duì)于本地資源敬飒,最好使用相對(duì) URL邪铲,在訪問(wèn)遠(yuǎn)程資源時(shí)再使用絕對(duì) URL。這樣就能消除歧義无拗,避免出現(xiàn)限制訪問(wèn)頭部或本地 cookie 信息等問(wèn)題带到。
-
跨瀏覽器 CORS
即使瀏覽器對(duì) CORS 的支持程度并不都一樣,但所有瀏覽器都支持簡(jiǎn)單的(非Preflight和不帶憑據(jù)的)請(qǐng)求英染,因此有必要實(shí)現(xiàn)一個(gè)跨瀏覽器的方法揽惹。檢測(cè) XHR 是否支持 CORS 的最簡(jiǎn)單方式,就是檢查是否存在 withCredentials 屬性四康,在結(jié)合檢測(cè) XDomainRequest 對(duì)象是否存在搪搏,就可以兼顧所有瀏覽器了。
function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if('withCredentials' in xhr) { // XHR 支持 CORS xhr.open(method, url, true); } else if ( typeof XDomainRequest != 'undefined') { // IE 通過(guò) XDR 支持 CORS xhr = new XDomainRequest(); xhr.open(method, url); } else { // 不支持直接返回 null xhr = null; } return xhr; }
SSE
SSE 是圍繞只讀 Comet 交互推出的 API闪金。
SSE API 用于創(chuàng)建到服務(wù)器的單向連接疯溺,服務(wù)器通過(guò)這個(gè)連接可以發(fā)送任意數(shù)量的數(shù)據(jù)。
服務(wù)端響應(yīng)的 MIME 類型必須是 text/event-stream哎垦。
SSE 支持短輪詢囱嫩、長(zhǎng)輪詢和 HTTP 流,而且能在斷開(kāi)連接時(shí)自動(dòng)確定何時(shí)重新連接漏设。
var source = new EventSource('myevents.php');
souce.onmessage = function(event) {
var data = event.data;
// process data;
}
SSE 實(shí)例對(duì)象具有 readyState 屬性墨闲。
- 0:正在連接到服務(wù)器
- 1:打開(kāi)了連接
- 2:表示關(guān)閉了連接
關(guān)閉一個(gè) EventSource 對(duì)象通過(guò)調(diào)用 close()
方法,要求強(qiáng)制斷開(kāi)連接并且不再重新連接郑口。
SSE 服務(wù)端發(fā)送的數(shù)據(jù) MIME 頭必須是 text/event-stream鸳碧。響應(yīng)的格式是純文本,且?guī)в?data:
前綴潘酗。
Web Sockets
Web Sockets 用于建立一個(gè)單獨(dú)的持久連接上提供全雙工杆兵、雙向通行。
使用 Web Sockets 必須使用對(duì)應(yīng)的協(xié)議 http://
=> ws://
仔夺、https://
=> wss://
使用自定義協(xié)議的好處是數(shù)據(jù)量小琐脏,不必?fù)?dān)心 HTTP 那樣字節(jié)級(jí)的開(kāi)銷。
HTTP => Web Sockets:
在 JavaScript 中創(chuàng)建了 Web Socket 后缸兔,會(huì)有一個(gè) HTTP 請(qǐng)求發(fā)送到服務(wù)器以發(fā)起連接日裙。客戶端在收到服務(wù)器響應(yīng)后惰蜜,建立的連接會(huì)使用 HTTP升級(jí) 從 HTTP協(xié)議交換為 Web Socket 協(xié)議昂拂。標(biāo)準(zhǔn)的 HTTP 無(wú)法實(shí)現(xiàn) Web Sockets,只有支持這種協(xié)議的專門(mén)服務(wù)器才能正常工作抛猖。
- 建立 Web Sockets 實(shí)例
var socket = new WebSockt('ws://www.example.com/server.php') - 發(fā)送請(qǐng)求
socket.send('hello World') // 通過(guò)WebSocket只能發(fā)送純文本內(nèi)容 - 處理收到的響應(yīng)
// 不支持 DOM 2 級(jí)事件偵聽(tīng)器格侯,必須使用 DOM 0 級(jí)語(yǔ)法分別定義每個(gè)事件處理程序鼻听。
socket.onmessage = function(event) {
var data = event.data;
// process data
}
SSE 和 Web Sockets 的選擇
面對(duì)具體用例,考慮是使用 SSE 還是 Web Sockets 時(shí)联四,可從以下兩個(gè)因素考慮:
- 是否有自由度建立和維護(hù) Web Sockets 服務(wù)器撑碴。
- 到底需不需要雙向通信(組合 XHR 和 SSE 同樣可以實(shí)現(xiàn)雙向通信)