前言
WebSocket 是 HTML5 引入的一項重要特性,它允許在瀏覽器和服務器之間建立雙向通信。
與 HTTP 請求-響應模式不同,WebSocket 允許在一個連接上進行持續的雙向數據傳輸,而不需要頻繁地建立和關閉連接。這使得 WebSocket 適用于實時性要求較高的應用,如聊天應用、實時廣播、股票市場等。
WebSocket 協議標識是 ws
(未加密)和 wss
(加密),類似于 HTTP 的 http
和 https
。
const socket = new WebSocket("ws://example.com/socket")
WebSocket 的特點
雙向通信
WebSocket 允許在同一個連接上同時發送和接收數據,從而實現實時雙向通信。
持久連接
一旦建立了 WebSocket 連接,它會保持打開狀態,直到顯式關閉連接。
低延遲
WebSocket 的雙向通信性質使得數據傳輸更加即時,相比傳統的 HTTP 請求,減少了通信延遲。
輕量級
與 HTTP 相比,WebSocket 協議頭較小,減少了數據傳輸時的開銷。
支持跨域
WebSocket 允許在不同域名之間進行通信,通過協議和安全措施確保通信安全性。
WebSocket 工作原理
握手階段: 客戶端發起一個 HTTP 請求到服務器,請求升級為 WebSocket 連接。服務器驗證請求后,將連接升級為 WebSocket。
雙向通信: 一旦 WebSocket 連接建立,客戶端和服務器可以在任何時候互相發送數據。數據可以以幀的形式傳輸,每個幀可以是文本或二進制數據。
關閉連接: 任一方可以在任何時候關閉 WebSocket 連接,觸發關閉握手。
WebSocket 的屬性
readyState
WebSocket 有多個屬性,其中 readyState
是最常用的,用來表示連接狀態,它定義以下幾個常量用來表示:
常量 | 值 | 說明 |
---|---|---|
WebSocket.CONNECTING | 0 | 表示正在連接中。 |
WebSocket.OPEN | 1 | 表示連接已建立,可以進行通信。 |
WebSocket.CLOSING | 2 | 表示連接正在關閉。 |
WebSocket.CLOSED | 3 | 表示連接已經關閉或者連接未成功。 |
示例代碼:
console.log(WebSocket.CONNECTING) // 0
console.log(WebSocket.OPEN) // 1
console.log(WebSocket.CLOSING) // 2
console.log(WebSocket.CLOSED) // 3
const socket = new WebSocket("ws://example.com/socket")
socket.onopen = event => {
console.log(socket.readyState) // 1
}
當然除了 readyState
還有一些別的屬性,但不常用,這里不做過多介紹。如果需要請參考:WebSocket - Web API 接口參考 | MDN
WebSocket 的四個事件
open
連接建立時觸發
const socket = new WebSocket("ws://example.com/socket")
// 當連接建立時
socket.onopen = event => {
console.log("WebSocket connection established.")
}
// 或者
socket.addEventListener("open", function (event) {
console.log("WebSocket connection established.")
})
message
客戶端接收服務端數據時觸發
const socket = new WebSocket("ws://example.com/socket")
// 當收到消息時
socket.onmessage = event => {
console.log("Message from server ", event.data)
}
// 或者
socket.addEventListener("message", function (event) {
console.log("Message from server ", event.data)
})
error
通信發生錯誤時觸發
const socket = new WebSocket("ws://example.com/socket")
socket.onerror = error => {
console.error("WebSocket error: " + error)
}
close
連接關閉時觸發
const socket = new WebSocket("ws://example.com/socket")
socket.onclose = event => {
console.log("WebSocket connection closed: " + event.code + " " + event.reason)
}
WebSocket 的兩個方法
Socket.send()
使用連接發送數據
// 創建 WebSocket 連接
const socket = new WebSocket("ws://example.com/socket")
socket.send("Client Message")
Socket.close()
關閉連接
// 創建 WebSocket 連接
const socket = new WebSocket("ws://example.com/socket")
// 關閉 WebSocket 連接
socket.close()
// 關閉 WebSocket 連接并指定狀態碼和原因
socket.close(1000, "Connection closed by user")
前端完整使用示例
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Example</title>
</head>
<body>
<h1>WebSocket Example</h1>
<div id="messages"></div>
<script>
// 創建 WebSocket 連接
const socket = new WebSocket("ws://example.com/socket")
// 當連接建立時
socket.onopen = event => {
console.log("WebSocket connection established.")
}
// 當收到消息時
socket.onmessage = event => {
console.log("Message from server ", event.data)
}
// 當連接關閉時
socket.onclose = event => {
console.log("WebSocket connection closed: " + event.code + " " + event.reason)
}
// 當發生錯誤時
socket.onerror = error => {
console.error("WebSocket error: " + error)
}
// 發送消息
function sendMessage() {
const message = prompt("Enter a message:")
if (message) {
socket.send(message)
}
}
// 關閉 WebSocket 連接
socket.close()
// 關閉 WebSocket 連接并指定狀態碼和原因
socket.close(1000, "Connection closed by user")
</script>
</body>
</html>
WebSocket 的心跳機制
心跳機制是一種民間說法,不是必須的,目的是為了保持 WebSocket 連接,防止連接意外斷開的一種機制。一般通過定期發送小型數據包(稱為心跳包或 ping)來維持 WebSocket 連接,以確保連接不會因為長時間沒有數據傳輸而被關閉。
以下是 WebSocket 心跳機制的基本原理:
定時發送心跳包: 客戶端和服務器都會定期發送心跳包,通常是一個空的或含有很少數據的消息,例如一個單字節的數據。這些心跳包的目的是告訴對方連接仍然活躍。
監測響應: 一旦一方發送了心跳包,另一方會回復一個響應(稱為 pong),以表示連接正常。
檢測連接狀態: 如果一方在預定的時間內未收到心跳包或響應,就可以推斷連接可能出現問題。在這種情況下,可以采取措施來重新建立連接或處理連接斷開的情況。
示例代碼:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Heartbeat Example</title>
</head>
<body>
<h1>WebSocket Heartbeat Example</h1>
<script>
const ws = new WebSocket("wss://example.com/socket") // 替換為實際的WebSocket地址
// 心跳間隔(毫秒)
const heartbeatInterval = 5000 // 每5秒發送一次心跳包
// 定時發送心跳包
const heartbeat = () => {
if (ws.readyState === WebSocket.OPEN) {
console.log("Sending heartbeat")
ws.send("heartbeat")
}
}
ws.addEventListener("open", event => {
console.log("WebSocket connection established.")
// 開始定時發送心跳包
setInterval(heartbeat, heartbeatInterval)
})
ws.addEventListener("message", event => {
if (event.data === "pong") {
console.log("Received pong response.")
} else {
console.log("Received message:", event.data)
}
})
ws.addEventListener("close", event => {
console.log("WebSocket connection closed:", event.code, event.reason)
})
ws.addEventListener("error", error => {
console.error("WebSocket error:", error)
})
</script>
</body>
</html>
WebSocket 和 HTTP/2 有什么異同點
WebSocket 和 HTTP/2 都支持 雙向通信,但有所區別。
用途
- WebSocket:主要用于實現實時、持續的雙向通信,比如聊天應用、游戲等場景。
- HTTP/2:主要用于優化單向請求-響應模式下的數據傳輸,特別是在加載網頁資源時提高性能。
通信模式
- WebSocket:通信模式是全雙工(Full-duplex),允許客戶端和服務器在同一連接上同時發送和接收數據。
- HTTP/2:通信模式是半雙工(Half-duplex),雖然支持服務器推送,但仍然需要在請求和響應之間切換。
連接維持
- WebSocket:連接建立后保持持久連接,適用于實時通信。
- HTTP/2:復用單一連接,減少了建立連接的開銷,但不像 WebSocket 那樣持久。
總結
WebSocket 使用 HTTP 協議進行連接,然后升級為 WebSocket 協議。在需要雙向通信的應用場景下非常有用,實時性非常高且不受跨域限制。