概述
本文是WebSocket系列的第一篇,主要介紹WebSocket相關的基礎協議知識和API。由於WebSocket的相關介紹在MDN中分佈較亂,初學者不太容易入門,因此通過本文將相關基礎知識和使用方法進行一個歸納和總結。
本文主要內容如下:
- WebSocket基礎概念介紹
- WebSocket協議初讀
- WebSocket 相關API淺析
- WebSocket線上上專案中的使用
通過本文,你能夠了解到WebSocket相關基礎知識,同時瞭解到WebSocket線上上環境中是如何使用的。
WebSocket介紹
WebSockets 是一個可以建立和伺服器間進行雙向會話的高階技術。通過這個API你可以向伺服器傳送訊息並接受基於事件驅動的響應,這樣就不用向伺服器輪詢獲取資料了。
上面是MDN中關於WebSocket的說明。其中雙向會話
指的是客戶端和服務端都能夠通過WebSocket來進行資料的互相傳遞,即服務端可以給客戶端推送資料,客戶端也可以通過WebSocket來傳遞資料。
為什麼要使用WebSocket
在不使用WebSocket時,如果我們需要建立一條長連線,有以下幾種方法:
- 輪詢
- 長輪詢(常用)
- SSE(Server Send Event)
下面,我們對這幾個都進行簡單的介紹。
輪詢
輪詢是最早在客戶端用來模擬長連線的一種方式。他通過客戶端定時想服務端傳送HTTP請求來模擬客戶端向服務端傳送資料,而服務端的資料則是在客戶端傳送HTTP請求後跟隨返回。
這種方案能夠讓客戶端的資料幾乎實時的到達,但是缺點也顯而易見:服務端的資料需要在客戶端的請求回來後才能帶回。如果HTTP請求的間隔太短,則會導致大量的網路開銷;如果間隔太長,這將導致資料傳遞的不及時。
長輪詢
長輪詢是在輪詢的基礎上改進的一種方式。在客戶端傳送HTTP請求且服務端收到請求時,服務端會先維持這個請求不返回。在特定的時間內(一般為30秒,因為通常HTTP判斷超時時間為30秒),如果服務端沒有資料,則回應這個請求;服務端有資料需要傳送時,則立即通過HTTP請求的響應將資料傳遞給客戶端。客戶端收到響應後,立即發起下一次的HTTP請求。
這種方案能夠解決輪詢中帶來的服務端資料不能及時傳遞的問題,但是帶來的網路花銷大的問題仍然無法解決。
SSE(Server Send Event)
SSE是一個新的協議,作用為服務端想客戶端推送資料。他通過自定義的SSE協議來實現單項的資料推送。SSE的缺點是資料只能從服務端像客戶端傳遞,而資料不能通過客戶端向服務端傳遞。
WebSocket能夠解決上述問題
WebSocket能夠有效的解決以下問題:
- 頻寬問題:WebSocket相對於HTTP來說協議頭更加小,同時按需傳遞。
- 資料實時性問題:WebSocket相對於輪詢和長輪詢來說,能夠實時傳遞資料,延遲更小。
- 狀態問題:相較於HTTP的無狀態請求,WebSocket在建立連線後能夠維持特定的狀態。
其他的優點可以參考維基百科。
WebSocket協議
瞭解了為什麼需要使用WebSocket,下面讓我們來了解下WebSocket協議相關的內容。
WebSocket協議是通過HTTP協議升級而來。只需要在HTTP協議基礎上增加兩次握手,即可建立WebSocket連線(如果是需要通過SSL加密,則還需要進行SSL握手過程),握手的部分詳情可以見WebSocket文件,下面我們簡單介紹以下Header相關欄位。
請求Header
請求Header如下:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
複製程式碼
其中:
Host: server.example.com
:表示將要連線的WebSocket地址。Connection: Upgrade
:需要升級HTTP連線。Upgrade: websocket
:將HTTP連線升級至WebSocket連線。Sec-WebSocket-Key:dGhlIHNhbXBsZSBub25jZQ==
:客戶端生成的WebSocket連線金鑰。Sec-WebSocket-Protocol: chat, superchat
:指定哪些協議是客戶端可以接受的。Sec-WebSocket-Version: 13
:WebSocket版本號。
響應Header
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
複製程式碼
其中:
Upgrade: websocket
:確認將HTTP連線升級至WebSocket連線。Connection: Upgrade
:確認升級HTTP連線。Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo
:服務端根據客戶端的連線金鑰生成的服務端金鑰。Sec-WebSocket-Protocol: chat
:選擇的WebSocket協議。
WebSocket API介紹
對WebSocket的協議有了一個初步的瞭解,下面讓我們看下,在具體的使用場景中,如何使用WebSocket。
WebSocket的API不多,下面我們就根據使用的順序:
- 建立連線
- 收到訊息
- 傳送訊息
- 關閉連線
來逐一進行介紹,具體的MDN資料可以見此處。
建立連線
WebSocket通過初始化例項來建立連線,通過open
事件回撥函式來確認連線建立成功,具體示例如下:
const webSocket = new WebSocket('ws://server.example.com');
webSocket.addEventListener('open', (event) => {
// 建立連線成功
});
複製程式碼
在WebSocket建立ws連線時,url可以是域名或者IP地址;但是當建立的連線是wss(加密WebSocket)時,url必須是域名,因為需要配置相應的證照,而證照是針對域名的。
收到訊息
WebSocket通過message
事件來接收訊息。
socket.addEventListener('message', function (event) {
console.log('Message from server', event.data);
});
複製程式碼
WebSocket可以傳遞String
、ArrayBuffer
和Blob
三種資料型別,因此在收到訊息時可能是其中的任意一種。其中,String
和ArrayBuffer
使用的最多。
-
如果是
String
型別,直接通過字串處理函式即可進行相關轉換,如JSON等格式。 -
如果是二進位制
ArrayBuffer
型別,則需要使用DataView
來進行處理,相關的內容將在本系列第二篇中進行介紹。
傳送訊息
WebSocket通過send
方法來傳送訊息。
webSocket.send(data);
複製程式碼
示例中的data
欄位,也有可能是收到訊息所說的String
、ArrayBuffer
和Blob
三種資料型別之一。其中,Blob
作為一種類檔案資料型別,再此不進行過多介紹。我們使用最多的就是String
和ArrayBuffer
。
String
型別只需要傳遞一個字串給send
方法作為引數即可。ArrayBuffer
型別則需要傳遞一個ArrayBuffer物件作為引數,相關的內容也將在本系列第二篇中進行介紹。
關閉連線
被動關閉
當服務端主動關閉WebSocket連線時,會通過WebSocket向客戶端傳送一個close資料包,WebSocket的close
事件會觸發。
webSocket.addEventListener('close', (closeEvent) => {
});
複製程式碼
注:當網路斷開時,WebSocket連線並不會被動關閉,因為沒有收到關閉的資料包。
主動關閉
客戶端可以通過WebSocket提供的close
方法來主動關閉長連線。
webSocket.close();
複製程式碼
目前該方法有兩個引數(在某些版本中不支援,詳情見MDN文件):
- 第一個參數列示關閉連線的狀態號,預設為1000,表示正常關閉。
- 第二個引數為關閉原因,是一個不長於123位元組的UTF-8文字。
總結
本文主要是介紹了一下WebSocket相關的基礎知識。
通過WebSocket的長連線,客戶端和服務端可以進行大量的資料傳輸而不會帶來相關的效能問題,這給Web端帶來了極大的功能增強。目前Web端可以使用WebSocket來進行IM相關功能開發,或者實時協作等需要與服務端進行大量資料互動的功能,並且不需要像之前一樣使用長輪詢的Hack方式來實現。
具體的使用方式和線上的使用問題,將會在本系列後幾篇部落格中進行介紹。