无法与Node.js服务器建立WebSocket连接,请求排查问题
问题描述
尝试搭建极简WebSocket服务器,但浏览器无法建立连接,加载HTML页面时出现错误:
error:index.html:9 WebSocket connection to 'ws://localhost:8080/?chatId=15432' failed:
服务器代码
const http = require("http"); const WebSocketServer = require("websocket").server; const server = http.createServer((req, res) => {}); const websocket = new WebSocketServer({ httpServer: server, autoAcceptConnections: false, }); const chats = new Map(); websocket.on("request", (request) => { let connection = request.accept(null, request.origin); console.log(connection); console.log(new Date() + " Connection accepted."); let chatId = request.resourceURL.query.chatId; if (!chats.has(chatId)) { chats.set(chatId, []); } chats.get(chatId).push(connection); connection.on("message", (message) => { console.log("Received Message: " + message.utf8Data); let chatConnections = chats.get(chatId); chatConnections.forEach((chatConnection) => { if (chatConnection !== connection) { chatConnection.sendUTF(message.utf8Data); console.log(connection); } }); }); connection.on("close", (reasonCode, description) => { console.log( new Date() + " Peer " + connection.remoteAddress + " disconnected." ); let chatConnections = chats.get(chatId); chatConnections.splice(chatConnections.indexOf(connection), 1); if (chatConnections.length === 0) { chats.delete(chatId); } }); }); server.listen(8080, "localhost", () => { console.log("listening on port 8080"); });
客户端代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script> let webSocket = new WebSocket("ws://localhost:8080?chatId=15432", null); webSocket.onopen = (event) => { webSocket.send("Hey guys, here's my first message"); console.log("Connection Opened Client"); }; webSocket.onclose = function () { console.log("WebSocket connection closed."); }; </script> </head> <body></body> </html>
预期能成功建立连接并接收客户端消息,但功能未实现,请问是否遗漏关键步骤?
问题分析与解决
你的代码存在两个核心问题导致连接失败:
Origin验证缺失
当autoAcceptConnections设为false时,服务器必须显式验证请求的Origin是否合法,否则浏览器会因为跨域安全策略拒绝连接。你的代码直接调用request.accept但未做任何Origin校验,这是连接失败的主要原因。子协议处理冗余
客户端创建WebSocket时传入null作为子协议参数,虽然服务器对应传入null能匹配,但更简洁的方式是两端都不指定子协议,避免不必要的协商干扰。
修改后的服务器代码
const http = require("http"); const WebSocketServer = require("websocket").server; const server = http.createServer((req, res) => {}); const websocket = new WebSocketServer({ httpServer: server, autoAcceptConnections: false, }); // 允许的Origin列表,根据实际运行环境调整 const allowedOrigins = ["http://localhost", "http://127.0.0.1", "null"]; const chats = new Map(); websocket.on("request", (request) => { // 验证请求Origin是否在允许列表内 const origin = request.origin; if (!allowedOrigins.includes(origin)) { request.reject(403, "Origin not allowed"); console.log(new Date() + " Connection rejected: Origin " + origin + " not allowed"); return; } // 接受连接,不指定子协议 let connection = request.accept(null, origin); console.log(connection); console.log(new Date() + " Connection accepted."); let chatId = request.resourceURL.query.chatId; if (!chats.has(chatId)) { chats.set(chatId, []); } chats.get(chatId).push(connection); connection.on("message", (message) => { console.log("Received Message: " + message.utf8Data); let chatConnections = chats.get(chatId); chatConnections.forEach((chatConnection) => { if (chatConnection !== connection) { chatConnection.sendUTF(message.utf8Data); } }); }); connection.on("close", (reasonCode, description) => { console.log( new Date() + " Peer " + connection.remoteAddress + " disconnected." ); let chatConnections = chats.get(chatId); if (chatConnections) { const index = chatConnections.indexOf(connection); if (index !== -1) { chatConnections.splice(index, 1); if (chatConnections.length === 0) { chats.delete(chatId); } } } }); }); server.listen(8080, "localhost", () => { console.log("listening on port 8080"); });
客户端代码调整
省略冗余的子协议参数,保持代码简洁:
let webSocket = new WebSocket("ws://localhost:8080?chatId=15432");
额外注意:如果是直接本地打开HTML文件(file://协议),浏览器Origin会是null,此时需要确保服务器allowedOrigins包含"null";更推荐用本地HTTP服务器(比如npx serve)启动HTML文件,这样Origin会是标准的HTTP地址,更符合生产环境场景。
内容的提问来源于stack exchange,提问作者bugsyb
相关产品推荐
相关产品推荐

