WebSocket是HTML5提供的全双工通信协议,支持客户端与服务端实时数据传输,适用于聊天、实时更新等场景,JS中使用时,先通过new WebSocket(url)创建连接,需监听关键事件:onopen触发后可调用send()发送数据;onmessage用于接收服务端返回的消息(通过event.data获取);onerror处理连接异常;onclose监听连接关闭,同时可通过readyState属性(0-4表示连接不同状态)监控连接状态,注意需处理跨域及连接断开后的重连逻辑,确保通信稳定。
WebSocket 使用教程:从零开始掌握 JavaScript 实时通信
WebSocket:从 HTTP 到实时通信的跨越
在传统的 Web 应用中,客户端与服务器之间的通信主要依赖于 HTTP 协议,HTTP 是一种无状态、请求-响应模式的协议:客户端主动发起请求,服务器处理并返回响应后,连接随即关闭(HTTP/1.x)或短暂保持(HTTP/2),这种模式天然无法满足实时数据推送的需求,例如在线聊天室、实时股票行情更新、在线多人游戏、协同编辑等场景,它们要求服务器能够主动、即时地将数据推送到客户端。
为了突破这一限制,WebSocket 协议应运而生,它基于 TCP 协议,在客户端和服务器之间建立一个持久的长连接,并支持全双工通信(即双方可以同时发送和接收数据),WebSocket 具有低延迟、高效率、轻量级的特点,使其成为构建实时 Web 应用的首选技术。
WebSocket 核心概念
连接建立:握手过程
WebSocket 连接并非直接建立,而是通过一个巧妙的 HTTP 升级(Upgrade)机制完成的:
- 客户端发起请求:客户端发送一个特殊的 HTTP 请求,包含以下关键头信息:
Upgrade: websocket:表明希望将连接升级到 WebSocket 协议。Connection: Upgrade:告知服务器这是一个连接升级请求。Sec-WebSocket-Key:一个由客户端生成的 Base64 编码的随机密钥,用于握手验证。Sec-WebSocket-Version:客户端支持的 WebSocket 协议版本(如 13)。
- 服务器响应升级:如果服务器支持 WebSocket,它会:
- 返回
101 Switching Protocols状态码。 - 包含
Upgrade: websocket和Connection: Upgrade头。 - 发送
Sec-WebSocket-Accept头,该值是Sec-WebSocket-Key与一个特定字符串("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")拼接后进行 SHA-1 哈希计算,再进行 Base64 编码的结果。
- 返回
- 连接建立:客户端验证
Sec-WebSocket-Accept值是否正确,若正确,握手成功,后续通信便直接基于 WebSocket 协议进行(使用自定义的数据帧格式),不再依赖 HTTP。
数据帧结构
WebSocket 数据传输采用自定义的帧(Frame)结构,而非简单的文本流,一个帧包含以下部分:
- FIN (1位):表示当前帧是否是消息的最后一帧,设置为 1 表示是最后一帧。
- RSV1, RSV2, RSV3 (各1位):保留位,通常为 0,除非协商了扩展(如压缩),否则必须为 0。
- Opcode (4位):标识数据帧类型:
0x0:连续帧(Continuation Frame),属于上一个消息的一部分。0x1:文本帧(Text Frame),数据为 UTF-8 编码的文本。0x2:二进制帧(Binary Frame),数据为二进制数据。0x8:关闭帧(Close Frame),用于关闭连接。0x9:Ping 帧(Ping Frame),用于心跳检测。0xA:Pong 帧(Pong Frame),对 Ping 帧的响应。
- Mask (1位):仅客户端发送的数据帧需要设置此位为 1,服务器发送的帧此位必须为 0,掩码用于防止某些代理服务器错误地缓存 WebSocket 数据(因为数据看起来可能像 HTTP 响应体)。
- Payload Length (7/16/64位):表示 Payload Data 的长度:
- 如果值 <= 125,直接使用该值。
- 如果值 == 126,接下来的 2 位(16位)表示长度。
- 如果值 == 127,接下来的 8 位(64位)表示长度。
- Masking Key (0或32位):Mask 位为 1,则紧跟 4 字节的掩码密钥。
- Payload Data:实际传输的数据,如果设置了 Mask 位,此数据需要使用掩码密钥进行异或(XOR)解密(客户端发送时是加密,服务器接收时解密)。
连接状态
WebSocket 对象的 readyState 属性(只读)精确反映连接的当前状态:
0(CONNECTING):连接正在建立中,尚未完成握手。1(OPEN):连接已成功建立,可以自由收发数据。2(CLOSING):连接正在关闭中,已发起关闭握手(客户端或服务器发送了关闭帧)。3(CLOSED):连接已关闭或未能建立。
JavaScript 中使用 WebSocket:核心 API
在浏览器端,通过 WebSocket 构造函数创建连接实例,核心 API 事件和方法如下:
创建 WebSocket 对象
// 参数:ws://(明文,不推荐生产环境)或 wss://(加密,强烈推荐)协议的 URL
const socket = new WebSocket('wss://yourdomain.com:8080/path'); // 强烈推荐使用 wss://
关键点:
ws://vswss://:wss://是 WebSocket 的安全版本(类似 HTTPS),使用 TLS 加密传输数据,生产环境必须使用wss://以防止中间人攻击和数据泄露。ws://仅适用于开发或内部可信网络。- URL 格式:可以包含路径(
/path)和查询参数(?key=value),服务器需能正确处理。
连接建立 (onopen 事件)
连接成功建立后,触发 onopen 事件,是发送数据的最佳时机。
// 方式一:直接赋值
socket.onopen = function(event) {
console.log('WebSocket 连接已成功建立!');
// 连接成功后可以立即发送数据
socket.send('Hello, Server! 这是客户端发送的第一条消息。');
};
// 方式二:使用 addEventListener (推荐,可绑定多个处理函数)
socket.addEventListener('open', (event) => {
console.log('WebSocket 连接已成功建立!(使用 addEventListener)');
socket.send('Hello, Server! (来自 addEventListener)');
});
接收消息 (onmessage 事件)
服务器发送数据时,触发