部署AWS EC2全栈应用时Angular无法连接Node.js WebSocket问题
解决AWS EC2实例上Angular+Node.js的WebSocket连接问题
问题背景
全栈应用部署到AWS EC2实例后,后端Node.js应用运行在5000端口,前端Angular由Nginx托管在80端口,同一实例内HTTP调用正常,但WebSocket连接失败:
- 最初客户端使用
ws://localhost:5000/ws连接时,出现Connection refused错误 - 修改为实例公网IP后,连接可建立但立即关闭,返回
CloseEvent code: 1005
当前Nginx server块配置:
listen 80; listen [::]:80; server_name _; # FRONTEND angular files location / { root /my_frontend_folder_path; } # BACKEND node/express proxy redirects location /api/ { proxy_pass http://localhost:5000/; } location /ws/ { proxy_pass http://localhost:5000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
客户端WebSocket代码:
this.socket = new WebSocket('ws://localhost:5000/ws'); this.socket.onopen = () => { console.log('WebSocket connection established.'); };
分步解决方案
1. 修正客户端WebSocket连接路径
浏览器中的localhost指向用户本地机器,而非EC2实例,必须通过Nginx代理连接WebSocket服务,使用相对路径或实例域名/IP:
// 推荐:自动适配HTTP/HTTPS和域名的写法 this.socket = new WebSocket(`${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`); // 或更简洁的相对路径(需确保前端页面部署在根路径) this.socket = new WebSocket('/ws');
2. 优化Nginx的WebSocket代理配置
当前/ws/的proxy_pass路径可能导致后端路由匹配问题,同时添加必要的超时和缓存配置:
location /ws { proxy_pass http://localhost:5000/ws; # 匹配后端WebSocket服务的路径,去掉末尾斜杠避免路径重写 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header 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; # 长连接超时设置,避免WebSocket被过早断开 proxy_connect_timeout 7d; proxy_send_timeout 7d; proxy_read_timeout 7d; proxy_cache_bypass $http_upgrade; # 禁用缓存WebSocket请求 }
3. 确保Node.js后端正确处理WebSocket升级请求
以ws库为例,确保后端服务监听/ws路径并正确处理HTTP升级:
const WebSocket = require('ws'); const express = require('express'); const http = require('http'); const app = express(); const server = http.createServer(app); const wss = new WebSocket.Server({ noServer: true }); // 处理HTTP升级到WebSocket server.on('upgrade', (request, socket, head) => { // 验证请求路径是否为/ws if (request.url !== '/ws') { socket.destroy(); return; } wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request); }); }); // 测试WebSocket连接 wss.on('connection', (ws) => { console.log('New WebSocket connection'); ws.send('Connection established'); ws.on('close', () => { console.log('WebSocket connection closed'); }); }); server.listen(5000, () => { console.log('Server running on port 5000'); });
4. 检查EC2实例的安全组与内部防火墙
- 安全组:无需开放5000端口到公网,所有请求通过Nginx的80端口代理即可
- 内部防火墙:确保EC2实例的iptables或firewalld允许localhost到5000端口的连接(默认允许,若修改过需验证)
5. 排查CloseEvent code 1005问题
code 1005表示连接被无代码关闭,常见原因:
- 后端WebSocket服务未监听
/ws路径,导致Nginx代理的请求无法被处理 - Nginx的
proxy_pass路径配置错误,将请求转发到了后端非WebSocket路由 - 后端未正确处理HTTP升级请求,直接关闭了连接
内容的提问来源于stack exchange,提问作者Estema
相关产品推荐
相关产品推荐

