概念定义
HTTP 由请求驱动:客户端问、服务器答。WebSocket 只协商一次,之后双方随时发送带帧的消息。帧头只有几字节,取代逐消息的完整 HTTP 语义,这才是效率来源。协议支持文本与二进制消息、ping-pong 保活与关闭语义。
工作机制
客户端发出带 Sec-WebSocket-Key 的 Upgrade 请求,服务器以 101 与证明摘要应答,连接随即切换协议。客户端到服务器的消息带掩码;ping、pong、close 等控制帧共用同一通道;子协议用于协商应用层消息模式。
使用场景
双向与高频流:聊天、协同编辑、多人游戏状态、遥测上报。纯服务器到客户端的场景用 SSE 更简单,还能享受 HTTP 缓存与自动重连。混合设计常用 HTTP 写入加 SSE 推送。
常见误区
消息仅在单连接内有序,跨重连的顺序保障是应用的责任。代理与负载均衡器会对无心跳的升级连接做空闲超时;故障后的重连风暴需要带抖动的退避。长寿命连接不应只信任升级时的认证,消息级确认也必须由应用实现。
代码示例
const DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
function pad(value) {
return String(value).padStart(2, "0");
}
export function formatHttpDate(date = new Date()) {
const value = date instanceof Date ? date : new Date(date);
if (Number.isNaN(value.getTime())) throw new RangeError("invalid date");
return DAYS[value.getUTCDay()] + ", "
+ pad(value.getUTCDate()) + " "
+ MONTHS[value.getUTCMonth()] + " "
+ value.getUTCFullYear() + " "
+ pad(value.getUTCHours()) + ":"
+ pad(value.getUTCMinutes()) + ":"
+ pad(value.getUTCSeconds()) + " GMT";
}
export function parseHttpDate(input) {
if (typeof input !== "string") throw new TypeError("input must be a string");
const value = Date.parse(input);
if (Number.isNaN(value)) throw new RangeError("invalid HTTP date");
return new Date(value);
}
import { Agent, fetch } from 'undici';
const agent = new Agent({
connections: 128,
pipelining: 10,
keepAliveTimeout: 60_000,
keepAliveMaxTimeout: 300_000,
});
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);
const res = await fetch('https://api.example.com/users', {
dispatcher: agent,
signal: controller.signal,
});
const users = await res.json();
clearTimeout(timer);
agent.close();