hermes-ws
v0.2.0
Published
A minimal RFC 6455 WebSocket server and Vite plugin for Node.js.
Maintainers
Readme
hermes-ws
一个基于 Node.js、面向 Vite 开发环境的最小 WebSocket Server 实现。
项目直接实现 RFC 6455 的基础帧、握手和连接生命周期,不依赖 ws 或 socket.io。
它的目标不是提供完整的 WebSocket 生态,而是提供一个体积小、依赖少、职责明确的基础 WebSocket Server。
特性
- HTTP Upgrade / 101 握手
Sec-WebSocket-Key- WebSocket Version 13
Upgrade/Connection校验- Text / Binary 消息
- Ping / Pong
- Close
- UTF-8 校验
- MASK 校验
- RSV 校验
- Control Frame 限制
maxPayload限制- TCP 粘包 / 拆包
initialData(握手 head 中携带的首帧)- 客户端集合
- Broadcast
- Server 生命周期
- Vite Plugin
明确不做
- 不支持消息分片
- 不支持 WebSocket Extensions
- 不支持 permessage-deflate
- 不负责认证
- 不负责重连
- 不负责心跳框架
- 不负责 RPC / room / subscription
- 不负责业务协议
业务协议应当建立在 hermes-ws 之上,而不是进入核心。
安装
Monorepo 内使用
import { hermesWs } from "#/hermes-ws";作为 npm 包使用
npm install hermes-wsimport { hermesWs } from "hermes-ws";Server 用法
import { createServer } from "node:http";
import { MinimalWebSocketServer } from "hermes-ws";
const wss = new MinimalWebSocketServer({
maxPayload: 16 * 1024 * 1024,
});
wss.on("connection", (ws) => {
console.log("client connected");
ws.on("message", (message, isBinary) => {
if (isBinary) {
ws.send(message);
} else {
ws.send(`echo: ${message}`);
}
});
ws.on("close", (code, reason) => {
console.log("client closed", code, reason.toString());
});
ws.on("error", (error) => {
console.error(error);
});
});
const server = createServer();
server.on("upgrade", (req, socket, head) => {
const { pathname } = new URL(req.url, "http://localhost");
if (pathname !== "/ws") return;
wss.handleUpgrade(req, socket, head, (ws) => {
wss.emit("connection", ws, req);
});
});
server.listen(3000);Vite Plugin 用法
import { defineConfig } from "vite";
import { hermesWs } from "hermes-ws";
export default defineConfig({
plugins: [
hermesWs({
path: "/ws",
maxPayload: 16 * 1024 * 1024,
onConnection(ws, wss) {
ws.on("message", (message) => {
wss.broadcast(message);
});
},
}),
],
});hermesWs 只负责:
- Vite upgrade
- 路径匹配
- WebSocket Server 生命周期
业务逻辑全部通过 onConnection 注入。
客户端用法
客户端不需要引入 hermes-ws,直接使用浏览器原生 WebSocket:
const ws = new WebSocket("ws://localhost:3000/ws");
ws.onopen = () => {
ws.send("hello");
};
ws.onmessage = (event) => {
console.log(event.data);
};
ws.onclose = (event) => {
console.log(event.code, event.reason);
};Connection API
ws.send("hello");
ws.send(Buffer.from([1, 2, 3]));
ws.ping();
ws.pong();
ws.close(1000, "bye");
ws.destroy();
ws.readyState;事件:
ws.on("message", (message, isBinary) => {});
ws.on("close", (code, reason) => {});
ws.on("error", (error) => {});
ws.on("pong", (data) => {});使用
MinimalWebSocket时建议始终监听error事件;Node.js 的EventEmitter对未处理的error事件会抛出异常。
Server API
const wss = new MinimalWebSocketServer({
maxPayload: 16 * 1024 * 1024,
});
wss.on("connection", (ws) => {});
wss.broadcast("hello everyone");
wss.broadcast("hello others", ws);
wss.close(callback);架构
Vite
│
▼
hermesWs() / MinimalWebSocketServer
│
├── handshake
├── connection
├── clients
└── broadcast
│
▼
MinimalWebSocket
│
├── send / ping / pong / close / destroy
└── message / close / error / pong
│
▼
Frame Codec
│
▼
TCP Socket测试
bun test
bunx tsc --noEmit当前测试覆盖:
- Frame 编解码
- 7 / 16 / 64 位长度
- Text / Binary
- Ping / Pong
- Close
- 粘包 / 拆包
initialData- MASK / RSV / FIN
- UTF-8
maxPayload- Broadcast
- Server 生命周期
- Vite Plugin
- 真实 TCP Integration Test
协议边界
支持:
TEXT + FIN
BINARY + FIN
PING + FIN
PONG + FIN
CLOSE + FIN拒绝:
TEXT + !FIN
BINARY + !FIN
CONTINUATION版本
当前版本:0.1.0
