🌐 WebSocket 前端使用详解
适用于:React / Vue / 原生JS / Next.js / Taro / UniApp 等前端框架
更新时间:2025-10-07
🧠 一、基本概念
WebSocket 是浏览器原生支持的实时通信协议,用于在客户端与服务器之间建立持续的双向连接。
核心对象:
const ws = new WebSocket("ws://localhost:8080");
🚀 二、快速上手示例
1️⃣ 创建连接
const socket = new WebSocket("ws://localhost:8080");
// 连接成功
socket.onopen = () => {
console.log("✅ WebSocket connected");
socket.send(JSON.stringify({ type: "join", user: "feipeng" }));
};
// 接收消息
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("📩 Received:", data);
};
// 连接关闭
socket.onclose = () => console.log("❌ WebSocket closed");
// 错误处理
socket.onerror = (error) => console.error("⚠️ WebSocket error:", error);
🧾 三、发送与接收消息
✅ 发送消息
function sendMessage(text) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: "chat", text }));
} else {
console.warn("WebSocket not open yet");
}
}
✅ 接收消息
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
if (message.type === "chat") {
console.log("💬", message.text);
} else if (message.type === "system") {
console.log("🔔", message.notice);
}
};
🧩 四、心跳检测机制(防止断开)
许多服务器会在空闲时关闭连接,因此需要定期发送“心跳包”维持连接。
✅ 心跳实现
let heartbeatTimer;
function startHeartbeat() {
heartbeatTimer = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: "ping" }));
}
}, 30000); // 每30秒一次
}
socket.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "pong") return; // 心跳响应不打印
console.log("📩", msg);
};
🔁 五、断线自动重连
当服务器重启或网络中断时,前端应自动重连。
let socket;
let reconnectTimer;
function connect() {
socket = new WebSocket("ws://localhost:8080");
socket.onopen = () => {
console.log("✅ Connected");
clearTimeout(reconnectTimer);
startHeartbeat();
};
socket.onmessage = (e) => console.log("📩", e.data);
socket.onclose = () => {
console.warn("🔄 Disconnected, retrying...");
clearInterval(heartbeatTimer);
reconnectTimer = setTimeout(connect, 2000); // 2秒后重连
};
socket.onerror = (err) => {
console.error("⚠️ Error:", err);
socket.close();
};
}
connect();
⚙️ 六、封装为通用模块(原生JS)
export class WebSocketClient {
constructor(url, onMessage) {
this.url = url;
this.onMessage = onMessage;
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log("✅ Connected");
this.startHeartbeat();
};
this.ws.onmessage = (e) => this.onMessage(JSON.parse(e.data));
this.ws.onclose = () => {
console.log("❌ Disconnected, retrying...");
clearInterval(this.heartbeat);
setTimeout(() => this.connect(), 2000);
};
this.ws.onerror = () => this.ws.close();
}
startHeartbeat() {
this.heartbeat = setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN)
this.ws.send(JSON.stringify({ type: "ping" }));
}, 30000);
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN)
this.ws.send(JSON.stringify(data));
}
}
使用示例:
const client = new WebSocketClient("ws://localhost:8080", (msg) => {
console.log("📩", msg);
});
client.send({ type: "chat", text: "Hello WebSocket" });
⚛️ 七、React 封装(自定义 Hook)
推荐前端项目直接用这个,支持自动重连 + 状态监听。
import { useEffect, useRef, useState } from "react";
export function useWebSocket(url) {
const wsRef = useRef(null);
const [messages, setMessages] = useState([]);
const [isConnected, setConnected] = useState(false);
useEffect(() => {
let reconnectTimer;
const connect = () => {
wsRef.current = new WebSocket(url);
wsRef.current.onopen = () => {
console.log("✅ Connected to", url);
setConnected(true);
};
wsRef.current.onmessage = (e) => {
const msg = JSON.parse(e.data);
setMessages((prev) => [...prev, msg]);
};
wsRef.current.onclose = () => {
console.warn("🔄 Disconnected, retrying...");
setConnected(false);
reconnectTimer = setTimeout(connect, 2000);
};
wsRef.current.onerror = (err) => {
console.error("⚠️ WebSocket error:", err);
wsRef.current.close();
};
};
connect();
return () => {
clearTimeout(reconnectTimer);
wsRef.current?.close();
};
}, [url]);
const send = (data) => {
if (wsRef.current?.readyState === WebSocket.OPEN)
wsRef.current.send(JSON.stringify(data));
};
return { send, messages, isConnected };
}
使用:
function Chat() {
const { send, messages, isConnected } = useWebSocket("ws://localhost:8080");
return (
<div>
<h2>WebSocket Chat {isConnected ? "🟢" : "🔴"}</h2>
<ul>
{messages.map((m, i) => (
<li key={i}>{m.text}</li>
))}
</ul>
<button onClick={() => send({ type: "chat", text: "Hello!" })}>
Send Message
</button>
</div>
);
}
🧰 八、最佳实践总结
| 需求 | 推荐实现方式 |
|---|---|
| 连接管理 | 自动重连 + 手动关闭 |
| 心跳机制 | ping/pong 保活 |
| 消息格式 | 统一 JSON 协议 {type, data} |
| 错误处理 | onerror + reconnect |
| 跨域 | 使用 wss:// 或在 Nginx 代理 |
| React 项目 | 封装 useWebSocket Hook |
| Vue 项目 | 封装 useWebSocket Composable |
🛠️ 九、调试与测试技巧
-
浏览器控制台输入:
new WebSocket("ws://localhost:8080")即可测试是否能连接。
-
使用
wscat(Node工具)测试:npm install -g wscat wscat -c ws://localhost:8080
📎 十、可选扩展
| 功能 | 说明 |
|---|---|
使用 socket.io | 简化兼容处理(断线重连内置) |
使用 reconnecting-websocket | 自动重连库 |
| TypeScript 支持 | 定义消息类型接口 |
| Redux/Zustand 状态同步 | 实时消息存储与 UI 同步 |