淺析CORS荣病、SSE 和 WebSockets

近期在重新看《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)雙向通信)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市朝墩,隨后出現(xiàn)的幾起案子醉拓,更是在濱河造成了極大的恐慌,老刑警劉巖收苏,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亿卤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鹿霸,警方通過(guò)查閱死者的電腦和手機(jī)排吴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)杜跷,“玉大人傍念,你說(shuō)我怎么就攤上這事矫夷「鹈疲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵双藕,是天一觀的道長(zhǎng)淑趾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)忧陪,這世上最難降的妖魔是什么扣泊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮嘶摊,結(jié)果婚禮上延蟹,老公的妹妹穿的比我還像新娘。我一直安慰自己叶堆,他們只是感情好阱飘,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著虱颗,像睡著了一般沥匈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忘渔,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天高帖,我揣著相機(jī)與錄音,去河邊找鬼畦粮。 笑死散址,一個(gè)胖子當(dāng)著我的面吹牛乖阵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播预麸,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼义起,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了师崎?” 一聲冷哼從身側(cè)響起默终,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎犁罩,沒(méi)想到半個(gè)月后齐蔽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡床估,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年含滴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丐巫。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谈况,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出递胧,到底是詐尸還是另有隱情碑韵,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布缎脾,位于F島的核電站祝闻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏遗菠。R本人自食惡果不足惜联喘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辙纬。 院中可真熱鬧豁遭,春花似錦、人聲如沸贺拣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)纵柿。三九已至蜈抓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昂儒,已是汗流浹背沟使。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渊跋,地道東北人腊嗡。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓着倾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親燕少。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卡者,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)客们,斷路器崇决,智...
    卡卡羅2017閱讀 134,696評(píng)論 18 139
  • Ajax:Asynchronous JavaScript + XML的簡(jiǎn)寫(xiě)。Ajax技術(shù)的核心是XMLHttpRe...
    exialym閱讀 878評(píng)論 0 8
  • 1. 緒論: AJAX技術(shù)的核心為XHR(XMLHttpRequest)對(duì)象AJAX功能:向服務(wù)器請(qǐng)求額外的數(shù)據(jù)而...
    xiaoguo16閱讀 240評(píng)論 0 1
  • 21.1 XMLHTTPRequest IE7之前是不支持XMLHTTPRequest的 只要readyState...
    進(jìn)擊的前端閱讀 320評(píng)論 0 1
  • 這篇文字我想字?jǐn)?shù)不會(huì)太多底挫,原因嘛恒傻,我就是這么感覺(jué)到的,不是不愿意寫(xiě)建邓,是寫(xiě)不出來(lái)盈厘。 這段時(shí)間的事我敘述一下。 我和她...
    呼吸的鯨魚(yú)閱讀 369評(píng)論 0 0