WebSocket 速查表
本文提供 WebSocket 开发的快速参考,包括常用 API、代码片段和配置选项。
浏览器 API
创建连接
const socket = new WebSocket('ws://localhost:8080');
const secureSocket = new WebSocket('wss://example.com/chat');
const socketWithProtocol = new WebSocket('ws://localhost:8080', 'chat-protocol');
const socketWithProtocols = new WebSocket('ws://localhost:8080', ['chat', 'json']);
连接状态
| 状态 | 值 | 说明 |
|---|---|---|
| CONNECTING | 0 | 连接中 |
| OPEN | 1 | 已连接 |
| CLOSING | 2 | 关闭中 |
| CLOSED | 3 | 已关闭 |
if (socket.readyState === WebSocket.OPEN) {
socket.send('Hello');
}
事件处理
socket.onopen = (event) => {
console.log('连接已建立');
};
socket.onmessage = (event) => {
console.log('收到消息:', event.data);
};
socket.onerror = (event) => {
console.error('连接错误');
};
socket.onclose = (event) => {
console.log('连接关闭:', event.code, event.reason);
};
发送消息
socket.send('文本消息');
socket.send(JSON.stringify({ type: 'chat', content: 'Hello' }));
socket.send(new ArrayBuffer(10));
socket.send(new Blob(['blob data']));
socket.send(new Uint8Array([1, 2, 3, 4]));
关闭连接
socket.close();
socket.close(1000, '正常关闭');
socket.close(3000, '自定义原因');
关闭码
| 代码 | 名称 | 说明 |
|---|---|---|
| 1000 | Normal | 正常关闭 |
| 1001 | Going Away | 端点离开 |
| 1002 | Protocol Error | 协议错误 |
| 1003 | Unsupported | 不支持的数据类型 |
| 1006 | Abnormal | 异常关闭 |
| 1008 | Policy Violation | 策略违规 |
| 1009 | Message Too Big | 消息过大 |
| 1011 | Internal Error | 内部错误 |
Node.js (ws 库)
安装
npm install ws
基本服务器
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (data) => {
ws.send('Echo: ' + data);
});
});
配置选项
const wss = new WebSocket.Server({
port: 8080,
host: '0.0.0.0',
maxPayload: 100 * 1024 * 1024,
clientTracking: true,
perMessageDeflate: {
zlibDeflateOptions: { level: 3 }
}
});
验证客户端
const wss = new WebSocket.Server({
port: 8080,
verifyClient: (info, callback) => {
const origin = info.origin;
if (origin !== 'http://localhost:3000') {
callback(false, 403, 'Forbidden');
return;
}
callback(true);
}
});
广播消息
function broadcast(wss, message) {
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}
心跳检测
function heartbeat() {
this.isAlive = true;
}
wss.on('connection', (ws) => {
ws.isAlive = true;
ws.on('pong', heartbeat);
});
setInterval(() => {
wss.clients.forEach((ws) => {
if (!ws.isAlive) return ws.terminate();
ws.isAlive = false;
ws.ping();
});
}, 30000);
Python (websockets)
安装
pip install websockets
基本服务器
import asyncio
import websockets
async def handler(websocket):
async for message in websocket:
await websocket.send(f"Echo: {message}")
async def main():
async with websockets.serve(handler, "localhost", 8080):
await asyncio.Future()
asyncio.run(main())
发送消息
await websocket.send("文本消息")
await websocket.send(json.dumps({"type": "chat"}))
await websocket.send(b"二进制数据")
接收消息
message = await websocket.recv()
async for message in websocket:
print(message)
关闭连接
await websocket.close(1000, "正常关闭")
Python (FastAPI)
基本用法
from fastapi import FastAPI, WebSocket
app = FastAPI()
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Echo: {data}")
消息类型
text = await websocket.receive_text()
data = await websocket.receive_bytes()
json_data = await websocket.receive_json()
await websocket.send_text("text")
await websocket.send_bytes(b"bytes")
await websocket.send_json({"key": "value"})
Go (gorilla/websocket)
安装
go get github.com/gorilla/websocket
基本服务器
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
defer conn.Close()
for {
_, msg, _ := conn.ReadMessage()
conn.WriteMessage(websocket.TextMessage, msg)
}
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Fatal(http.ListenAndServe(":8080", nil))
}
读写消息
messageType, message, err := conn.ReadMessage()
err = conn.WriteMessage(websocket.TextMessage, []byte("text"))
err = conn.WriteJSON(map[string]string{"key": "value"})
var data map[string]string
err = conn.ReadJSON(&data)
关闭连接
err := conn.WriteMessage(websocket.CloseMessage,
websocket.FormatCloseMessage(1000, "正常关闭"))
conn.Close()
Nginx 配置
upstream websocket {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name example.com;
location /ws {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}
常用代码片段
自动重连客户端
class ReconnectingWebSocket {
constructor(url) {
this.url = url;
this.socket = null;
this.reconnectAttempts = 0;
this.connect();
}
connect() {
this.socket = new WebSocket(this.url);
this.socket.onopen = () => this.reconnectAttempts = 0;
this.socket.onclose = () => {
if (this.reconnectAttempts++ < 5) {
setTimeout(() => this.connect(), 1000 * this.reconnectAttempts);
}
};
}
send(data) {
if (this.socket?.readyState === WebSocket.OPEN) {
this.socket.send(data);
}
}
}
连接管理器
class ConnectionManager {
constructor() {
this.connections = new Map();
}
add(id, ws) {
this.connections.set(id, ws);
}
remove(id) {
this.connections.delete(id);
}
broadcast(message, exclude = null) {
const data = JSON.stringify(message);
this.connections.forEach((ws, id) => {
if (id !== exclude && ws.readyState === WebSocket.OPEN) {
ws.send(data);
}
});
}
}
心跳管理
class Heartbeat {
constructor(socket, interval = 30000) {
this.socket = socket;
this.interval = interval;
this.missed = 0;
this.maxMissed = 3;
}
start() {
this.timer = setInterval(() => {
if (++this.missed > this.maxMissed) {
this.socket.close();
return;
}
this.socket.send(JSON.stringify({ type: 'ping' }));
}, this.interval);
this.socket.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.type === 'pong') this.missed = 0;
});
}
stop() {
clearInterval(this.timer);
}
}
消息队列
class MessageQueue {
constructor(maxSize = 100) {
this.queue = [];
this.maxSize = maxSize;
}
add(message) {
if (this.queue.length >= this.maxSize) {
this.queue.shift();
}
this.queue.push(message);
}
flush(send) {
while (this.queue.length) {
send(this.queue.shift());
}
}
}
调试技巧
Chrome DevTools
- 打开开发者工具 (F12)
- 切换到 Network 标签
- 筛选 WS (WebSocket)
- 点击连接查看消息
日志包装
function createLoggedSocket(url) {
const socket = new WebSocket(url);
const originalSend = socket.send.bind(socket);
socket.send = (data) => {
console.log('→', data);
return originalSend(data);
};
socket.addEventListener('message', (e) => {
console.log('←', e.data);
});
return socket;
}
常见问题
Q: 连接立即断开
检查:
- URL 是否正确
- 服务器是否运行
- Origin 是否被允许
- 是否需要认证
Q: 消息发送失败
检查:
readyState是否为 OPEN- 消息格式是否正确
- 是否有速率限制
Q: 连接超时
解决:
- 实现心跳机制
- 增加 Nginx
proxy_read_timeout - 检查网络稳定性
Q: 跨域问题
解决:
- 服务器配置
CheckOrigin - 使用正确的 Origin
- 使用 wss:// 协议