nginx+WebSocket踩坑记录
- 1、场景
- 2、问题原因
- 3、解决方法
- 1、路径未匹配
- 2、未发送心跳包
- 3、转发请求配置为websocket链接
- 4、配置nginx中的读取超时参数
- 5、wss链接通过nginx转发时,$http_upgrade未取到值,导致转到服务器缺少Upgrade请求头,未识别为websocket链接,导致链接404报错(具体体现:ws链接正常,wss链接404)
- 其他错误
- 1、使用wss协议报错
- 报错信息
- 问题原因
- 公网服务器注意事项(使用wss协议)
1、场景
需要反向代理转发websocket链接。
2、问题原因
1、nginx路径未匹配上
2、链接上后,在默认的http链接时长中没有发送心跳包,nginx自动关闭http链接,一般默认为1分钟
3、http链接转发后并没有升级为websockt链接(Bad Request 400错误)
4、websocket长链接1分钟后自动关闭
5、wss链接通过nginx转发时,$http_upgrade未取到值,导致转到服务器缺少Upgrade请求头,未识别为websocket链接,导致链接404报错(具体体现:ws链接正常,wss链接404)
3、解决方法
1、路径未匹配
检查nginx路径配置,如下配置:
正确匹配地址:ws://localhost:8080/websocket/xxx
如果是location /websocket {…}
ws://localhost:8080/websocket/xxx这个地址是匹配不到的,就会报504错误(开启access_log日志可看到)。
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#日志输出格式
log_format main '$remote_addr - $remote_user [$time_local] "$host:$server_port" "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
#记录nginx日志
access_log logs/access.log main;
server {
listen 8080;
server_name localhost;
location /websocket/ {
proxy_pass http://127.0.0.1:8808/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
2、未发送心跳包
1、js文件发送心跳,写一个定时器定时发送心跳信息
var ws;
ws = new WebSocket("ws://127.0.0.1:8808/websocket/a");
var heartCheck = {
timeout: 20000,//20ms,后台设置了60秒过期
timeoutObj: null,
serverTimeoutObj: null,
reset: function(){
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
this.start();
},
start: function(){
var self = this;
this.timeoutObj = setTimeout(function(){
ws.send("心跳信息");
self.serverTimeoutObj = setTimeout(function(){
ws.close();//如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
}, self.timeout);
}, this.timeout)
},
}
function initWebSorket() {
ws.onopen = function () {
console.log("连接成功。");
heartCheck.start();
};
ws.onmessage = function (evt) {
console.log("发送消息。");
heartCheck.reset();
};
ws.onclose = function (){
console.log("连接关闭");
reconnct();
};
ws.onerror = function (){
console.log("连接异常");
reconnct();
};
}
function reconnct() {
ws = null;
ws = new WebSocket("ws://127.0.0.1:8808/websocket/a");
console.log("重新链接");
initWebSorket();
}
3、转发请求配置为websocket链接
配置三行请求头升级为websocket链接
nginx官网文档配置websocket:http://nginx.org/en/docs/http/websocket.html
# 动态决定connection的值,当$http_upgrade为默认值时,则connection的值为keep-alive。当$http_upgrade为websocket时,connection的值为upgrade
map $http_upgrade $connection_upgrade {
default keep-alive; #默认为keep-alive 可以支持 一般http请求
'websocket' upgrade; #如果为websocket 则为 upgrade 可升级的。
}
location /websocket/ {
proxy_pass http://127.0.0.1:8808/;
#配置以下三行即可
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
4、配置nginx中的读取超时参数
nginx转发请求默认读取数据超时时间为1分钟
location /websocket/ {
proxy_pass http://127.0.0.1:8808/;
#配置以下三行即可
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300;
}
5、wss链接通过nginx转发时,$http_upgrade未取到值,导致转到服务器缺少Upgrade请求头,未识别为websocket链接,导致链接404报错(具体体现:ws链接正常,wss链接404)
location /websocket/ {
proxy_pass http://127.0.0.1:8808/;
#配置以下三行即可
proxy_http_version 1.1;
# 直接固定Upgrade的值
proxy_set_header Upgrade "websocket"
proxy_set_header Connection "upgrade";
proxy_read_timeout 300;
}
其他错误
1、使用wss协议报错
报错信息
VM338:1 Mixed Content: The page at ‘’ was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint ‘ws://ip:端口’. This request has been blocked; this endpoint must be available over WSS.
问题原因
1、本身页面的连接为https连接,所以不能用ws协议
解决方法:打开http页面,就可以使用ws协议了
公网服务器注意事项(使用wss协议)
1、服务器未对目标服务开放端口443
解决方法:打开控制面板-安全-防火墙-出入站规则-入站规则-开放端口即可
2、腾讯云安全组未开放端口(腾讯服务器)
解决方法:打开腾讯云服务器管理后台,开放端口即可