Docker部署Node-RED等多容器搭配Nginx反代后前端WebSocket无法接收数据
Nginx反向代理Docker容器化服务时WebSocket连接故障排查
部署架构说明
- 基于Docker Compose编排3个独立容器服务:Node-RED、InfluxDB、基于
nginx:alpine镜像构建的静态网页服务。网页内置图片资源,通过WebSocket通道接收Node-RED推送的数据,动态切换页面展示的图片 - 宿主机侧部署独立非容器化Nginx,搭配Let's Encrypt证书,对上述3个容器服务做反向代理
- 故障触发条件:所有服务未做容器化部署时流程可正常运行,全量迁移到Docker容器后,WebSocket链路无法正常接收推送数据

前端原有WebSocket连接逻辑代码
function startConnect() { document.getElementById('dt').click(); socket = new WebSocket("ws://mywebsite.com:1880/ws/test"); socket.onmessage = function(e) {onMessageArrived(e.data)} console.log("connected"); socket.onopen = function() {socket.send("1")}; } // 收到服务端推送消息的处理逻辑 function onMessageArrived(message) { console.log("onMessageArrived: " + message); var obj = JSON.parse(message); document.getElementById("image1").src = "myimage/" + obj.L + "_DL.png"; document.getElementById("image2").src = "myimage/" + obj.M + obj.F + obj.S + "_" + obj.Z48_70 + "_M.png"; document.getElementById("image3").src = "myimage/" + obj.V + obj.V + "_X"; }
已尝试的无效调整方案
- 调整方向1:将原WebSocket连接地址
ws://mywebsite.com:1880/ws/test改为指向网页容器暴露端口的ws://mywebsite.com:6100/ws/test,因站点已启用HTTPS,触发浏览器安全策略拦截明文ws连接请求 - 调整方向2:改为直连网页容器内网IP的
ws://192.170.0.6:6100/ws/test,跨网段访问限制导致TCP连接无法建立 - 调整方向3:改为走Nginx反向代理路径的连接地址
new WebSocket("ws://mywebsite/webpage/ws/test"),由Nginx规则匹配转发到网页容器对应IP端口,依然无法正常接收WebSocket推送数据
故障根因与修复方案
补全Nginx反向代理的WebSocket协议支持配置
普通HTTP反向代理默认无法完成WebSocket的握手升级流程,需要在Nginx站点配置中,对应WebSocket路径的location块下追加协议升级参数:location /ws/test { # 转发目标指向Node-RED容器的映射端口,不要错误代理到静态网页容器 proxy_pass http://127.0.0.1:1880; proxy_http_version 1.1; # 核心配置:传递WebSocket升级请求头 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 延长长连接超时时间,避免WebSocket被主动断开 proxy_read_timeout 86400; proxy_send_timeout 86400; # 传递基础请求头信息 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路径的转发目标指向了静态网页容器,而WebSocket的数据源是Node-RED服务,路径匹配规则需要对应到Node-RED的实际服务地址
修正前端WebSocket连接的协议判断逻辑
由于站点已启用HTTPS,浏览器会拦截从HTTPS页面发起的明文ws连接请求,需要根据当前页面的访问协议自动匹配WebSocket连接协议:function startConnect() { document.getElementById('dt').click(); // 根据页面协议自动选择wss/ws连接,避免HTTPS下的安全拦截 const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws'; socket = new WebSocket(`${wsScheme}://mywebsite.com/ws/test`); socket.onmessage = function(e) {onMessageArrived(e.data)} console.log("connected"); socket.onopen = function() {socket.send("1")}; }调整后无需将1880、6100等非标准端口暴露到公网,所有流量统一通过443端口走Nginx反向代理,完全符合浏览器安全策略要求。
校验Docker容器网络连通性
- 确认Node-RED容器的WebSocket节点监听地址为
0.0.0.0,而非容器内部的127.0.0.1,否则宿主机侧的Nginx无法访问容器内的WebSocket服务 - 确认Docker Compose的端口映射规则正常:Node-RED容器的1880端口已正确映射到宿主机对应端口,能够被宿主机的Nginx进程正常访问
- 确认Node-RED容器的WebSocket节点监听地址为
内容的提问来源于stack exchange,提问作者Zakaria ZOUAOUI
相关产品推荐
相关产品推荐

