跳到主要内容

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']);

连接状态

状态说明
CONNECTING0连接中
OPEN1已连接
CLOSING2关闭中
CLOSED3已关闭
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, '自定义原因');

关闭码

代码名称说明
1000Normal正常关闭
1001Going Away端点离开
1002Protocol Error协议错误
1003Unsupported不支持的数据类型
1006Abnormal异常关闭
1008Policy Violation策略违规
1009Message Too Big消息过大
1011Internal 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

  1. 打开开发者工具 (F12)
  2. 切换到 Network 标签
  3. 筛选 WS (WebSocket)
  4. 点击连接查看消息

日志包装

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:// 协议