引言
WebSocket 作为现代 Web 开发的"实时通信神器",已经成为构建交互式应用的标配技术。本文将带你从基础概念到高级应用,全面掌握 WebSocket 的核心技术,并解锁那些鲜为人知的高阶技巧!
一、告别轮询,拥抱实时
1.1 为什么需要 WebSocket?
传统 HTTP 的痛点:
- 单向通信:只能客户端发起请求
- 高延迟:需要不断轮询获取新数据
- 资源浪费:每次请求都携带完整头部
javascript
// 传统轮询示例
setInterval(async () => {
const response = await fetch('/api/updates');
// 处理数据...
}, 5000); // 每5秒请求一次
1.2 WebSocket 核心优势
- 全双工通信:客户端和服务端可以同时发送消息
- 低延迟:建立连接后即时传输
- 高效:只需一次握手,后续通信头部极小
1.3 使用Express
和@wll8/express-ws
创建一个基础的WebSocket服务端
javascript
const express = require("express");
const expressWs = require(`@wll8/express-ws`);
const { app, wsRoute } = expressWs(express());
const port = 3000;
app.ws(`/`, (ws, req) => {
// const {params, query} = req
ws.send(`abc`);
ws.on('message', (message) => {
console.log('收到客户端消息:', message);
ws.send(`正常连接`);
});
});
// 定义一个简单的路由,当访问根路径时返回 "Hello, World!"
app.get("/", (req, res) => {
res.send("Hello, World!");
});
// 启动服务器并监听指定端口
app.listen(port, () => {
console.log(`服务器正在运行,访问地址为 http://localhost:${port}`);
});
1.4 基础客户端 WebSocket 连接
javascript
const socket = new WebSocket("ws://127.0.0.1:3000");
// 连接打开
socket.onopen = () => {
console.log("WebSocket 连接已建立");
socket.send("Hello Server!");
};
// 接收消息
socket.onmessage = (event) => {
console.log("收到消息:", event.data);
};
// 连接关闭
socket.onclose = () => {
console.log("WebSocket 连接已关闭");
};
二、构建健壮的 WebSocket 应用
2.1 心跳检测机制
防止连接意外中断:
javascript
let heartbeatInterval;
// 连接打开
socket.onopen = () => {
console.log("WebSocket 连接已建立");
socket.send("Hello Server!");
heartbeatInterval = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'heartbeat' }));
}
}, 15 * 1000); // 每15秒发送一次心跳
};
// 连接关闭
socket.onclose = () => {
console.log("WebSocket 连接已关闭");
clearInterval(heartbeatInterval);
};
2.2 消息序列化与协议设计
推荐消息格式:
json
{
"id": "unique-message-id",
"type": "message|notification|command",
"timestamp": 1625097600000,
"payload": {}
}
处理示例:
javascript
// 接收消息
socket.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
switch (message.type) {
case "notification":
break;
case "message":
console.log(message.payload);
break;
default:
console.warn("未知消息类型:", message.type);
}
} catch (error) {
console.error("消息解析失败:", error);
}
};
三、一个简单的聊天示例系统
3.1 前端实现
javascript
class ChatClient {
constructor(url) {
this.socket = new WebSocket(url);
this.setupEventHandlers();
}
setupEventHandlers() {
this.socket.onmessage = (event) => {
const message = JSON.parse(event.data);
this.renderMessage(message);
};
this.socket.onclose = () => {
console.log("关闭连接");
};
}
sendMessage(text) {
console.log(this.socket.readyState);
if (this.socket.readyState === WebSocket.OPEN) {
const message = {
id: Math.floor(Math.random() * 10),
type: "chat-message",
timestamp: Date.now(),
payload: { text },
};
this.socket.send(JSON.stringify(message));
}
}
renderMessage(message) {
let content = `${new Date(message.timestamp).toLocaleString()}:${message.payload.text}`;
console.log(content);
}
}
let client = new ChatClient("ws://127.0.0.1:3000");
setTimeout(() => {
client.sendMessage("你好");
}, 1000);
4.2 服务端实现(Node.js)
javascript
const express = require("express");
const expressWs = require(`@wll8/express-ws`);
const { app, wsRoute } = expressWs(express());
const port = 3000;
app.ws(`/`, (ws, req) => {
// const {params, query} = req
let msg = {
id: "login",
type: "message",
timestamp: Date.now(),
payload: {
message: "消息",
},
};
ws.send(JSON.stringify(msg));
ws.on("message", (message) => {
console.log("收到客户端消息:", message);
// ws.send(`正常连接`);
});
});
// 定义一个简单的路由,当访问根路径时返回 "Hello, World!"
app.get("/", (req, res) => {
res.send("Hello, World!");
});
// 启动服务器并监听指定端口
app.listen(port, () => {
console.log(`服务器正在运行,访问地址为 http://localhost:${port}`);
});
总结
如果你喜欢本教程,记得点赞+收藏!关注我获取更多JavaScript开发干货。