如何让WebSocket实现实时通信?Express集成问题排查
问题描述
我在后端用Express集成WebSocket,前端用浏览器原生WebSocket API,目前能实现客户端和服务器互发消息,但所有操作必须刷新页面才触发。WebSocket应该支持实时通信:比如修改服务器文件里的消息内容后,要立刻在浏览器控制台显示变更;修改客户端脚本的消息内容后,要立刻在服务器控制台显示变更(我已经用nodemon跑服务器,代码变更应该快速生效)。但现在必须刷新页面发起请求,服务器才会升级连接并返回消息,请问我在代码或概念上有遗漏吗?
后端代码(app.js)
const express = require('express') const app = express() const path = require('path') const WebSocketServer = require('websocket').server; app.set('view engine', 'html'); app.use(express.static(path.join(__dirname, '/public'))) const port = 8080 app.get('/', (req, res) => { res.render('index') }) const server = app.listen(port, () => { console.log(`Example app listening on port ${port}`) }) wsServer = new WebSocketServer({ httpServer: server }); function originIsAllowed(origin) { return true; } wsServer.on('request', function(request) { if (!originIsAllowed(request.origin)) { request.reject(); console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.'); return; } var connection = request.accept(null, request.origin); console.log((new Date()) + ' Connection accepted.'); connection.on('message', function(message) { if (message.type === 'utf8') { console.log('Received Message: ' + message.utf8Data); connection.sendUTF("server says hi"); } else if (message.type === 'binary') { console.log('Received Binary Message of ' + message.binaryData.length + ' bytes'); connection.sendBytes(message.binaryData); } }); connection.on('close', function(reasonCode, description) { console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); }); });
前端代码(client.js)
const socket = new WebSocket('ws://localhost:8080'); // Connection opened socket.addEventListener('open', function (event) { socket.send('Hello to Server!'); }); // Listen for messages socket.addEventListener('message', function (event) { console.log('Message from server ', event.data); });
问题分析与解决
核心问题拆解
你的代码能建立WebSocket连接并收发消息,但实时性需求没落地,本质是两个关键缺失:
- 服务器没有主动推送能力,无法在代码变更后给已连接客户端发消息
- 客户端没有自动重连机制,代码变更或服务器重启后无法自动恢复连接
具体解决步骤
1. 服务器端:维护连接池,实现主动推送
现在服务器只在收到客户端消息时被动回复,需要新增连接存储逻辑,支持主动向所有在线客户端推送消息:
// 新增:存储所有活跃的WebSocket连接 const activeConnections = []; wsServer.on('request', function(request) { // ... 保留原有的origin检查、连接接受逻辑 ... var connection = request.accept(null, request.origin); console.log((new Date()) + ' Connection accepted.'); // 新增:将新连接加入连接池 activeConnections.push(connection); connection.on('message', function(message) { // ... 保留原有的消息处理逻辑 ... }); connection.on('close', function(reasonCode, description) { console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.'); // 新增:连接断开时从连接池移除 const index = activeConnections.indexOf(connection); if (index !== -1) { activeConnections.splice(index, 1); } }); }); // 新增:主动广播消息的函数,修改服务器消息后直接调用即可 function broadcastToAllClients(message) { activeConnections.forEach(conn => { if (conn.connected) { conn.sendUTF(message); } }); } // 示例:比如你修改了服务器回复内容,调用这个函数就能立刻推送给所有客户端 // broadcastToAllClients("新的服务器回复内容");
2. 客户端:添加自动重连,适配服务器重启/代码变更
客户端代码变更后浏览器不会自动刷新,服务器重启会断开现有连接,需要给客户端加自动重连逻辑:
let socket; function initWebSocket() { socket = new WebSocket('ws://localhost:8080'); socket.addEventListener('open', function (event) { console.log('WebSocket连接成功'); socket.send('Hello to Server!'); }); socket.addEventListener('message', function (event) { console.log('Message from server ', event.data); }); // 新增:连接断开后自动重试 socket.addEventListener('close', function() { console.log('连接断开,3秒后尝试重连'); setTimeout(initWebSocket, 3000); }); // 新增:连接错误处理 socket.addEventListener('error', function(err) { console.error('WebSocket连接出错:', err); }); } // 初始化连接 initWebSocket();
如果想让客户端代码变更后自动刷新页面,可以用Vite、Webpack Dev Server这类带热重载的工具,修改代码后浏览器会自动刷新并重建WebSocket连接。
3. 概念澄清
WebSocket的"实时通信"指连接建立后,双方可随时主动收发消息,而非"代码变更自动同步"。代码变更的实时生效需要额外处理:
- 服务器端:通过连接池主动推送变更内容
- 客户端:通过自动重连或热重载,发送新的消息内容
内容的提问来源于stack exchange,提问作者Deke
相关产品推荐
相关产品推荐

