【Web微知識系列】雙向溝通的技術,什麼是Websocket?
進入本篇章前建議您可以先了解以下兩個篇章,主要是介紹單向過程中的訂閱概念:
這種雙向溝通機制主要是為了更即時的反應,舉例來說今天我們有一個應用是即時語音辨識,那麼勢必會有一個互動的過程,使用者端進行錄音後,即時的送到伺服器進行辨識並將辨識結果即時呈現於畫面上時,就必須透過這種雙向溝通機制才能完成。
簡介
傳統的Http是一種Stateless的傳輸方式, 因此不會維持原本狀態, 而是需要更新、新增、查詢...等操作時才進行請求, 因此假設有即時性互動的應用時就不太適用了, 因為每進行一個動作就要向Server端發送請求, 而每次的請求都必須經過交握式連接的過程, 在效能上就不是那麼理想了, Websocket允許瀏覽器跟Server端只經過一次的交握過程, 就能建立一條長連接的溝通管道, 並透過這條管道進行「雙向傳輸」。
Websocket與TCP、HTTP的關係
- Websocket與HTTP屬於應用層, 同樣都是基於TCP來進行傳輸, 而進行Handshake時也會透過HTTP進行, 但真正傳輸資料時就不必經過HTTP的方式。
- 與HTTP一樣可以進行加密傳輸, HTTP的部份為
https
, Websocket則為wss
。
為什麼要使用Websocket?
其實以往我們網頁資料刷新有以下幾種方式可以實作:
Polling
這種方式是早期透過Javascript定時(setInterval
、setTimeout
)來向後端請求最新資料並呈現於頁面之上, 這麼做的好處是容易實現, 但我們並不知曉Server端何時會更新, 只能傻傻的定時獲取, 造成的影響就是頻寬的浪費以及資料呈現不即時。
Long-Polling
長時間輪詢的方式就是收到前端請求後, Server端會等待, 若這段時間有資料就會將最新資料回傳給前端, 因此等待的這段期間Client什麼事情也不用做, 等待資料回傳後再發送下一個請求, 雖然長時間的連接解決了Polling開銷的問題, 但如果在更新資料很頻繁的狀況下也會造成連續的Polling的動作產生, 未必效能較佳。
Server Sent Events
這種方式比較少被使用, 因為SSE能做的功能Websocket也能完成, 差別只是雙向溝通還是單向溝通而已, 不過在某些應用上, 瀏覽器不太需要傳遞資料給Server端, 例如: 股市行情、即時新聞...等, 只需要接收Server端的最新資料即可, 不太需要主動發送, 當然實作起來也較容易, 簡單來說就是伺服端單向的推送資料給瀏覽器。
Websocket
以上幾個方式的共同點就是都基於HTTP進行傳輸, 而我們也知道HTTP的傳輸為了確保正確性會帶有較多的標頭...等資訊, 而Websocket只有一開始確定連線時會走HTTP以外, 之後的傳輸都不是基於HTTP, 因此傳輸上會來的更有效率, 且提供了雙向溝通的功能。
常見的線上互動遊戲、雲端協作、線上聊天...等, 若使用上述的幾種方式都有延遲的議題存在,因此需要即時互動的應用就非常適合使用Websocket的方式來進行實作。
建立連接
- 以javascript來說, 通常我們在建立Websocket物件的時候, Browser就開始進行Handshake的過程。
var socket = new WebSocket("ws://127.0.0.1:8080/ws")
- 建立連線成功後,會發送支援的版本號、主機地址...等資訊給Server端。
Accept-Encoding: gzip, deflate Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 Cache-Control: no-cache Connection: Upgrade Host: 127.0.0.1:8080 Origin: http:*//127.0.0.1:8080* Pragma: no-cache Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: sZrnswRjM0ZXxxmAIJhrvQ== Sec-WebSocket-Version: 13 Upgrade: websocket User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36
- Server端收到後會回傳狀態碼101及相關資訊。
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 3zg/SIKvYpT51lJJKbF4WjFuCTY= Access-Control-Allow-Origin: * Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
- 如果過程失敗的話就會進入
onerror
的handler, 成功的話就代表可以開始傳輸資料。
如何確保連線狀態
假設連線的過程中發生了以下兩種狀況:
- 長時間不發送訊息或者防火牆阻擋了連接, Server端無法得知。
- Client端與Server端之間斷開網路, Server端也未感知。
此時就需要一種Heartbeat的機制, 來偵測彼此的連線是否存活。
- 由發送端發送ping訊號給接收端。
- 接收端成功收到之後, 回應pong訊號給發送端。
- 成功接收到pong訊號, 代表連線正常。
發送端 -> ping -> 接收端 發送端 <- pong <- 接收端
對於Client端來說就有開發者提供了Heartbeat的套件websocket-heartbeat-js, 讓我們開發前端時省去自行實做的時間。
📝 Web微知識系列文章
- 【Web微知識系列】 關於Web的同源政策(Same Origin Policy)
- 【Web微知識系列】 跨來源資源共用(Cross-Origin Resource Sharing, CORS)
- 【Web微知識系列】 你的資料如何被偷走? Web安全篇 - 跨站請求偽造(CSRF )
- 【Web微知識系列】 潛藏的危機 - 跨網站指令碼(XSS)
- 【Web微知識系列】 關於Web的安全內容政策 - Content Security Policy (CSP)
- 【Web微知識系列】訂閱技術的基石,RSS Feed是什麼?
- 【Web微知識系列】系統之間的訂閱機制,Webhook是什麼?
喜歡撰寫文章的你,不妨來了解一下:
Web3.0時代下為創作者、閱讀者打造的專屬共贏平台 - 為什麼要加入?
歡迎加入一起練習寫作,賺取知識,累積財富!