先铺垫一个核心类比:
把WebSocket 连接想象成「你和朋友的电话通话 」------ 拨号(new WebSocket)建立连接,说话(send)发消息,听对方说(onmessage)收消息,电话接通(onopen)才能聊天,电话断了(onclose)要重拨,电话出问题(onerror)要处理,通话状态(readyState)能看是不是在通话中。
一、构造函数:new WebSocket(url) ------ 发起「电话拨号」,建立连接

1. 是什么?
这行代码的作用是「让前端(浏览器)主动联系后端的 WS 服务」,就像你用手机拨朋友的电话号码,发起通话请求。
2. 关键细节(初学者必看)
url:后端 WS 服务的「地址」(类似朋友的电话号码),格式必须是ws://或wss://开头(前面讲过,ws是明文,wss是加密,生产环境用wss);- 示例:
ws://localhost:8080/chat(本地后端 WS 服务,端口 8080,聊天接口/chat); - 带登录态(你的项目需要):
ws://localhost:8080/chat?token=xxx(拼接token让后端认得出你,避免未登录就聊天)。
- 示例:
- 执行后返回一个「WS 实例」(比如赋值给
const ws = new WebSocket(...)),后续所有操作(发消息、听消息)都靠这个ws对象。
3. 简单代码示例
javascript
// 拨号:连接后端 WS 服务(替换成你的真实地址)
const ws = new WebSocket('ws://localhost:8080/chat?token=用户登录后的Token');
4. 为什么需要?
没有这一步,前端和后端就没有「双向通信的通道」,后续的收发消息都无从谈起(就像没拨号,没法和朋友聊天)。
二、发送消息:ws.send(data) ------ 对着电话「说话」,传递消息

1. 是什么?
通过前面创建的 ws 实例,把前端的消息(比如你输入的聊天内容)发送给后端,就像你对着电话说话,声音通过电话线传给朋友。
2. 关键细节(初学者必踩坑)
data:要发送的消息内容,只能是字符串、Blob(二进制文件,比如图片)、ArrayBuffer(二进制数据) ;- 最常用:字符串(比如聊天文本),如果要发复杂数据(比如包含用户名、消息内容、时间),需要转成 JSON 字符串(后端再转回去);
- 错误示例:
ws.send({ content: '你好', name: '小明' })(直接发对象会报错!); - 正确示例:
ws.send(JSON.stringify({ content: '你好', name: '小明' }))(用JSON.stringify转成字符串)。
- 错误示例:
- 最常用:字符串(比如聊天文本),如果要发复杂数据(比如包含用户名、消息内容、时间),需要转成 JSON 字符串(后端再转回去);
- 必须在「连接成功后」调用:如果刚拨号(
new WebSocket)就调用send,会失败(就像电话还没接通,你说话朋友也听不见)。
3. 简单代码示例
javascript
// 假设用户输入的聊天内容存在 inputValue 里
const inputValue = '今天天气真好!';
// 说话:发送消息给后端(转成 JSON 字符串,方便后端解析)
ws.send(JSON.stringify({
content: inputValue,
from: '当前登录用户名',
time: new Date().toLocaleTimeString()
}));
4. 为什么需要?
这是前端主动发消息的唯一方式(比如你输入聊天内容后点「发送」,本质就是调用 ws.send)。
三、接收消息:ws.onmessage = (event) => { ... } ------ 听电话「接话」,接收后端消息

1. 是什么?
这是一个「事件监听」:告诉浏览器 "如果后端通过 WS 给我发消息了,就执行这个函数",就像你把耳朵贴在电话上,等着听朋友说话。
2. 关键细节
event:是浏览器自动传递的「消息事件对象」,里面的event.data就是后端发来的消息内容;- 后端发的是字符串:直接用
event.data; - 后端发的是 JSON 字符串(最常见):需要用
JSON.parse(event.data)转成对象才能用;
- 后端发的是字符串:直接用
- 只要连接没断,这个监听会一直生效(后端随时发消息,前端都能收到)。
3. 简单代码示例
javascript
// 听电话:接收后端发来的消息
ws.onmessage = (event) => {
// 后端发的是 JSON 字符串,转成对象
const message = JSON.parse(event.data);
console.log('收到后端消息:', message);
// 比如 message 是 { content: '你也好!', from: '小红', time: '14:30' }
// 之后可以把这个消息添加到聊天列表,界面就显示出来了
};
4. 为什么需要?
WebSocket 是「双向通信」,不仅前端能发,后端也能主动推消息(比如别人给你发聊天内容,后端会推给你),onmessage 就是接收这些推送的唯一方式。
四、状态监听:onopen / onerror / onclose ------ 监听电话的「接通、故障、挂断」状态
这三个都是「事件监听」,对应 WS 连接的三个关键状态,必须处理,否则会出现 "发消息没反应""断连了不知道" 等问题。
1. ws.onopen ------ 电话「接通」了(连接成功)
-
是什么?:连接成功建立后,浏览器会自动执行这个函数(就像电话接通后,你听到 "嘟" 的一声,知道可以说话了)。
-
什么时候用?:发送第一条消息必须在这里面(或者判断连接成功后再发),避免连接没通就发消息失败。
-
代码示例:
javascript// 电话接通了:连接成功回调 ws.onopen = () => { console.log('WS 连接成功!可以发消息了~'); // 比如连接成功后,发送一条"进入聊天"的消息 ws.send(JSON.stringify({ content: '我进入聊天啦!', from: '当前登录用户名' })); };
2. ws.onerror ------ 电话「出故障」了(连接错误)
-
是什么?:连接过程中出错(比如后端服务没启动、地址写错、网络断了),浏览器会执行这个函数。
-
什么时候用?:给用户提示 "聊天连接异常",或者触发重连。
-
代码示例:
javascript// 电话出故障:连接错误回调 ws.onerror = (error) => { console.error('WS 连接出错了!', error); // 给用户显示提示(比如在页面上弹个框) alert('聊天连接异常,请稍后再试~'); };
3. ws.onclose ------ 电话「挂断」了(连接关闭)
-
是什么?:连接断开时(比如用户离开聊天页、后端主动关闭、网络中断),浏览器会执行这个函数。
-
什么时候用?:处理「重连逻辑」(比如断连后 3 秒自动重新拨号),避免用户还在聊天页但发不出消息。
-
代码示例:
javascript// 电话挂断了:连接关闭回调 ws.onclose = (event) => { console.log('WS 连接断开了~', event.code, event.reason); // 断连重连(简单版):3 秒后重新创建连接 setTimeout(() => { console.log('正在重新连接...'); // 重新拨号(这里可以复用之前的 new WebSocket 逻辑) const newWs = new WebSocket('ws://localhost:8080/chat?token=xxx'); // 注意:新连接需要重新绑定 onmessage、onopen 等事件 ws = newWs; // 替换原来的 ws 实例 }, 3000); };
4. 为什么需要这三个监听?
WS 连接不是永久稳定的(可能断网、后端重启),没有这些监听,你不知道连接是不是通的、出错了怎么办、断了怎么恢复,聊天功能会非常不稳定(就像打电话不知道通没通、断了没反应)。
五、连接状态:ws.readyState ------ 查看电话当前是「拨号中 / 接通 / 挂断」

1. 是什么?
ws 实例的一个属性,用来「实时查看当前连接的状态」,就像你看手机屏幕,知道电话是 "正在拨号""通话中" 还是 "已挂断"。
2. 四个核心状态值(不用记,用的时候查)
WS 定义了 4 个状态常量,对应 readyState 的值:
| 状态常量 | 数值 | 含义(类比电话) | 能不能发消息? |
|---|---|---|---|
WebSocket.CONNECTING |
0 | 正在拨号(连接中) | 不能 |
WebSocket.OPEN |
1 | 通话中(连接成功) | 能 |
WebSocket.CLOSING |
2 | 正在挂断(关闭中) | 不能 |
WebSocket.CLOSED |
3 | 已挂断(连接关闭) | 不能 |
3. 怎么用?(初学者常用场景)
发送消息前,先判断 readyState 是不是 1(OPEN),避免断连后发消息失败:
javascript
const sendMessage = (content) => {
// 先判断连接是否可用
if (ws.readyState === WebSocket.OPEN) {
// 连接正常,发送消息
ws.send(JSON.stringify({ content }));
} else {
// 连接不可用,提示用户
alert('当前聊天连接不可用,请稍等~');
}
};
4. 为什么需要?
比如用户断网了(readyState 变成 3),但还在输入消息点发送,如果不判断,ws.send 会失败且没有提示,用户会疑惑 "为什么发不出去";判断后可以给出明确提示,提升体验。
六、初学者必看:完整流程串起来(代码整合)
把上面的所有点整合到一起,就是一个完整的「React 中 WS 收发消息」基础逻辑(你练手 Demo 时可以直接参考这个结构):
javascript
import { useState, useEffect } from 'react';
function Chat() {
const [ws, setWs] = useState(null); // 存储 WS 实例
const [messages, setMessages] = useState([]); // 聊天消息列表
const [inputValue, setInputValue] = useState(''); // 输入框内容
// 1. 组件挂载时,创建 WS 连接(useEffect 处理副作用)
useEffect(() => {
// 拨号:创建连接(带登录 Token)
const newWs = new WebSocket(`ws://localhost:8080/chat?token=${localStorage.getItem('token')}`);
// 2. 连接成功(onopen)
newWs.onopen = () => {
console.log('WS 连接成功');
setWs(newWs); // 存储 WS 实例到状态
};
// 3. 接收消息(onmessage)
newWs.onmessage = (event) => {
const newMsg = JSON.parse(event.data);
setMessages([...messages, newMsg]); // 更新消息列表
};
// 4. 连接错误(onerror)
newWs.onerror = (err) => {
console.error('WS 错误:', err);
alert('聊天连接异常');
};
// 5. 连接关闭(onclose)
newWs.onclose = () => {
console.log('WS 连接断开');
// 3 秒后重连
setTimeout(() => {
// 重新执行 useEffect(这里简化处理,实际可以抽成函数)
}, 3000);
};
// 组件卸载时关闭连接(清理副作用)
return () => {
newWs.close();
};
}, []); // 空依赖:组件挂载时只创建一次连接
// 6. 发送消息函数
const handleSend = () => {
if (!inputValue.trim()) return; // 空消息不发
if (ws && ws.readyState === WebSocket.OPEN) {
// 连接正常,发送消息
ws.send(JSON.stringify({
content: inputValue,
from: '当前用户名',
time: new Date().toLocaleTimeString()
}));
setInputValue(''); // 清空输入框
} else {
alert('连接不可用,无法发送');
}
};
return (
<div>
{/* 消息列表 */}
<div>{messages.map((msg, idx) => <div key={idx}>{msg.from}: {msg.content}</div>)}</div>
{/* 输入框 + 发送按钮 */}
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="输入消息..."
/>
<button onClick={handleSend}>发送</button>
</div>
);
}
最后总结(初学者牢记)
- 先
new WebSocket(url)拨号建连接,得到ws实例; - 靠
ws.onopen确认连接成功,再用ws.send(data)发消息(data 转字符串); - 靠
ws.onmessage收后端消息(转成对象用); - 靠
onerror处理错误,onclose处理重连; - 发消息前用
ws.readyState === 1判断连接是否可用。