關(guān)于 websocket 跨域的一個奇怪問題…
點(diǎn)擊關(guān)注公眾號,Java干貨及時送達(dá)
作者:fredalxin
地址:https://fredal.xin/websocket-cors-problem
最近在建設(shè)websocket長連接網(wǎng)關(guān),過程中遇到一件比較奇怪的事情,做下簡單的記錄。
所以我們的期望是瀏覽器與websocket網(wǎng)關(guān)進(jìn)行handshark請求時可以帶上jwt-token cookie。

結(jié)果自然是不行的,服務(wù)端并沒有收到來自*.xx.com的cookie。于是開始考慮可能和跨域行為有關(guān)系。
CORS
CORS 是一種用于解決跨域的w3c標(biāo)準(zhǔn),全稱為"跨域資源共享"(Cross-origin resource sharing)。它允許瀏覽器向跨源服務(wù)器,發(fā)出 XMLHttpRequest 請求,從而克服了 AJAX 只能同源使用的限制。
CORS 基于 http 協(xié)議關(guān)于跨域方面的規(guī)定,使用時,客戶端瀏覽器直接異步請求被調(diào)用端服務(wù)端,在響應(yīng)頭增加響應(yīng)的字段,告訴瀏覽器后臺允許跨域。到底什么是跨域?推薦看下。
概括的說,CORS就是服務(wù)端對跨域權(quán)限的控制,由一組標(biāo)準(zhǔn)的header來控制客戶端的跨域行為,不同瀏覽器對于CORS的實(shí)現(xiàn)均有不同。
常用的CORS header主要有:
Access-Control-Allow-Origin :指示請求的資源能共享給哪些域,可以是具體的域名或者*表示所有域。 Access-Control-Allow-Credentials :指示當(dāng)請求的憑證標(biāo)記為 true 時,是否響應(yīng)該請求。 Access-Control-Allow-Headers :用在對預(yù)請求的響應(yīng)中,指示實(shí)際的請求中可以使用哪些 HTTP 頭。 Access-Control-Allow-Methods:指定對預(yù)請求的響應(yīng)中,哪些 HTTP 方法允許訪問請求的資源。
CORS處理請求的流程如下:
判斷當(dāng)前請求是否簡單請求。 如果不是簡單請求,則會使用OPTIONS方法先發(fā)起一個預(yù)檢請求(PreFlight),預(yù)檢請求通過返回的response里設(shè)置了對應(yīng)的header并匹配上了才會進(jìn)行下一步具體的請求。 預(yù)檢請求后會發(fā)起實(shí)際請求,但會根據(jù)返回的response header來決定請求行為,例如根據(jù)服務(wù)端設(shè)置的Access-Control-Allow-Credentials值來決定請求是否攜帶當(dāng)前域的cookie。
這里涉及到的簡單請求和非簡單請求的概念,那么簡單請求和非簡單請求有什么區(qū)別呢?
若請求滿足所有下述條件,則該請求可視為簡單請求:
使用了下列 HTTP 方法:GET、HEAD、POST。 只用了以下header:Accept、Accept-Language、Content-Language、Content-Type(有額外限制)、DPR、Downlink、Save-Data、Viewport-Width、Width。 請求中的任意XMLHttpRequestUpload 對象均沒有注冊任何事件監(jiān)聽器;XMLHttpRequestUpload 對象可以使用 XMLHttpRequest.upload 屬性訪問。 請求中沒有使用 ReadableStream 對象。
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: ws.xx.com
Origin: http://www.xx.com
Sec-WebSocket-Key: sB9cRrP/a9NdMgdcy2VJFX==
Sec-WebSocket-Version: 11
Upgrade: websocket
Connection: Upgrade
我們使用的是Netty來構(gòu)建websocket網(wǎng)關(guān),Netty支持CORS很簡單:
CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build();
pipeline.addLast(new CorsHandler(corsConfig));
結(jié)果是什么呢?我們的websocket服務(wù)端正確拿到了*.xx.com的cookie,并完成了后續(xù)鑒權(quán)工作。另外,關(guān)注公眾號Java技術(shù)棧,在后臺回復(fù):面試,可以獲取我整理的 Java 系列面試題和答案,非常齊全。
websocket需要CORS么?
所以真相是什么呢?websocket也需要CORS支持來避免跨域問題么?
google任何websocket與跨域相關(guān)的問題都會告訴你,websocket本身就是支持跨域的,websocket本身沒有同源策略!也就是說,在第一幅圖中,我們應(yīng)該不作任何事就可以把xx.com的cookie帶到ws.xx.com的websocket網(wǎng)關(guān)上去,這似乎和我們實(shí)際情況不符。
我們使用的是chrome,后來突發(fā)奇想試了下firefox與safari,結(jié)論是這兩者不用配置任何CORS相關(guān)屬性就可以把cookie帶上。難道這是chrome的一個bug?翻了翻網(wǎng)絡(luò),找到了一個似乎可以應(yīng)征的bug report:https://bugs.chromium.org/p/chromium/issues/detail?id=947413






關(guān)注Java技術(shù)棧看更多干貨


