Nginx路由中WebSocket请求丢失问题排查求助
WebSocket连接异常排查与修复
问题描述
我正尝试从公网IP的JavaScript应用向Node.js服务器建立WebSocket连接,使用pm2和Nginx做路由转发。虽然WebSocket请求返回200状态码,但服务器日志里完全看不到任何WebSocket相关调用记录,仅能看到服务启动时的端口初始化等日志。
Nginx配置文件(/etc/nginx/sites-available/my_app.com,已软链至sites-enabled)
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream websocket { server localhost:3010; } upstream backend { server localhost:3000; } server { listen 80; listen [::]:80; server_name my_app.com www.my_app.com --My website ip address for testing--; # these are allowed to use unsecured connection... location / { proxy_pass http://backend; } location /ws { proxy_pass http://websocket; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } }
服务器端相关文件
app.js
const express = require("express") const http = require("http") const { log } = require("./system/global") const app = express() const http_server = http.createServer(app) const PORT = 3000 require("./system/serve_path")(http_server, 'frontend', app, express) require("./system/serve_socket").start(PORT) http_server.listen(PORT, ()=> log("Listening on port " + PORT))
./system/globals.js
const fs = require('fs') exports.log = (msg) => { let now = new Date().toISOString() let log_msg = `${now}: ${msg}` console.log(log_msg) let log_folder = './logs' if (!fs.existsSync(log_folder)) { fs.mkdirSync(log_folder) } let log_file = `${log_folder}/log.log` if (!fs.existsSync(log_file)) { fs.writeFileSync(log_file, '') } else { let stats = fs.statSync(log_file) let fileSize = stats.size if (fileSize > 1073741824) { let now = new Date().toISOString() let new_file_name = `${log_folder}/log_${now}.log` fs.renameSync(log_file, new_file_name) fs.writeFileSync(log_file, '') } } fs.appendFile(log_file, '\n' + log_msg, (err) => { if (err) { console.log(err) } }) } exports.load_system = (module_name) => { return require(`./system/${module_name}`) } exports.load_socket = (module_name) => { return require(`./socket/${module_name}`) }
./system/serve_path.js
module.exports = (server, path, app, express) => { app.use(express.static(path)) }
./system/serve_socket.js
const websocket = require('ws') const { log } = require('./global') exports.start = (port) => { let socket_port = port + 10 log("Socket started on port: " + socket_port) let wss = new websocket.Server({port: socket_port}) wss.on('connection', function(ws) { log('Socket connected') ws.on('open', on_message) ws.on('error', on_message) ws.on('message', on_message) }) } const on_message = (msg) => { console.log('Received from client: %s', msg); log('Socket Message: %s', msg); ws.send('Socket Message: ' + msg); } const on_error = (err) => { log('Socket Error: %s', err); } const on_open = () => { log('Socket connection opened'); }
问题排查与修复
1. 事件绑定与作用域错误
serve_socket.js存在两个关键问题:
- 将
open、error、message事件全部绑定到on_message函数,逻辑混乱; on_message中引用的ws变量不在当前作用域,会导致报错。
修复后的serve_socket.js:
const websocket = require('ws') const { log } = require('./global') exports.start = (port) => { let socket_port = port + 10 log("Socket started on port: " + socket_port) let wss = new websocket.Server({port: socket_port}) wss.on('connection', function(ws) { log('Socket connected') // 绑定对应事件到正确处理函数,传递ws实例 ws.on('message', on_message.bind(null, ws)) ws.on('error', on_error.bind(null, ws)) ws.on('close', () => log('Socket connection closed')) }) } const on_message = (ws, msg) => { console.log('Received from client: %s', msg); log('Socket Message: %s', msg); ws.send('Socket Message: ' + msg); } const on_error = (ws, err) => { log('Socket Error: %s', err); ws.close() }
2. 客户端连接路径验证
确保客户端WebSocket连接地址为ws://your-domain/ws,而非直接访问3010端口——Nginx已经做了反向代理,直接访问端口可能被防火墙或Nginx拦截。
3. Nginx配置优化
在location /ws中添加超时与转发头配置,避免连接被意外断开:
location /ws { proxy_pass http://websocket; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 长连接超时设置 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; }
4. 验证步骤
- 重启Nginx:
sudo nginx -s reload - 重启Node.js服务:
pm2 restart your-app-name - 查看服务器日志,确认是否有
Socket connected日志输出 - 检查客户端控制台,确认无连接错误且连接URL正确
内容的提问来源于stack exchange,提问作者Michael Tot Korsgaard
相关产品推荐
相关产品推荐

