nginx开启websocket代理功能
使用Nginx代理WebSocket的时候,客户端与服务器握手成功后,如果在60秒内没有数据交互,就会自动断开连接。因为Nginx默认的断开链接时间为60秒,为保持长连接,可有两种解决方法。
第一种修改nginx配置
[root@web conf]# cat test.shnne.com.conf
server {
listen 80;
server_name test.shnne.com;
location / {
proxy_pass http://192.168.1.10:88;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#websocket
proxy_read_timeout 600s; #这条是保持10分钟才断开,方式默认60s就自动断开
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}下面依次介绍各参数作用:
location /shnne/websocket {
# 反向代理转发地址
proxy_pass http://test.shnne.com/websocket;
# 超时时间
proxy_read_timeout 600;
# Websocket Support
proxy_http_version 1.1;
proxy_set_header upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 其他设置
# 代理是否支持重定向
proxy_redirect off;
#远端真实地址
proxy_set_header X-Real-IP $remote_addr;
# HTTP请求的主机域名
proxy_set_header Host $host;
# 反向代理之后转发之前的ip地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# nginx代理
proxy_set_header X-Nginx-Proxy true;
}
升级http1.1到 websocket协议。另外有一个特别值得注意的地方是,如果websocket服务器在收到websocket握手包,查看Origin信息与所在域信息不符的话。会直接拒绝服务。这点很坑,我花了接近半天的时间来找为什么连不上的原因,最后竟然发现是Origin 必须和请求地址在一个域,不然会被拒绝访问并且返回403.
【补充】
NGINX支持WebSocket。
对于NGINX将升级请求从客户端发送到后台服务器,必须明确设置Upgrade和Connection标题。
这也算是上面情况所非常常用的场景。
HTTP的Upgrade协议头机制用于将连接从HTTP连接升级到WebSocket连接,Upgrade机制使用了Upgrade协议头和Connection协议头。
为了让Nginx可以将来自客户端的Upgrade请求发送到后端服务器,Upgrade和Connection的头信息必须被显式的设置。
【注意】
在nginx的配置文件中,如果当前模块中没有proxy_set_header的设置,则会从上级别继承配置。
继承顺序为:http, server, location。
如果在下一层使用proxy_set_header修改了header的值,则所有的header值都可能会发生变化,之前继承的所有配置将会被丢弃。
所以,尽量在同一个地方进行proxy_set_header,否则可能会有别的问题。
按照上述方法设置好后,我们可以发现,如果在10分钟之内没有数据交互的话,websocket连接就会自动断开,所以这种方式还是有点问题,如果我页面停留时间超过十分钟而且又没有数据交互的话,连接还是会断开的,所以需要同时结合第二种方法.
第二种:在Nginx延时基础上,前端在超时时间内做心跳检测
var socket;
// 心跳检测,每隔一段时间检测连接状态,如果处于连接中,就像Server主动发送消息,来重置Server段与客户端的最大连接时间,如果已经断开,发起重连
var heartCheck = {
// 9分钟发起一次心跳,比Server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间
timeout: 550000,
serverTimeoutObj: null,
reset: function () {
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
this.serverTimeoutObj = setInterval(function () {
if (socket.readyState == 1) {
console.log("连接状态,发送消息保持连接");
socket.send("ping");
// 如果获取到消息,说明连接正常,重置心跳检测
heartCheck.reset().start();
} else {
console.log("断开连接,尝试重连");
connect();
}
}, this.timeout)
}
};
function connect() {
if (typeof WebSocket == "undefined") {
console.log("不支持WebSocket!");
} else {
console.log("支持WebSocket!");
}
socket = new WebSocket("ws://47.99.57.113:1234/club/websocket");
// 打开事件
socket.onopen = function () {
heartCheck.reset().start();
console.log("socket 已打开");
};
// 获得消息事件
socket.onmessage = function (msg) {
heartCheck.reset().start();
console.log(msg.data);
};
// 关闭事件
socket.onclose = function () {
console.log("Socket 已关闭")
};
// 发生错误
socket.onerror = function () {
console.log("Socket 发生了错误")
};
}
function close() {
socket.close();
}另外一个检测
// websocket连接
var websocket_connected_count = 0;
var onclose_connected_count = 0;
function newWebSocket() {
var websocket = null;
// 判断当前环境是否支持websocket
if(window.WebSocket){
if(!websocket){
var ws_url ="wss://"+domain+"/updatewebsocket";
websocket = new WebSocket(ws_url);
}
}else{
Tip("not support websocket");
}
// 连接成功建立的回调方法
websocket.onopen = function(e) {
heartCheck.reset().start(); // 成功建立连接后,重置心跳检测
Tip("connected successfully")
}
// 连接发生错误,连接错误时会继续尝试发起连接(尝试5次)
websocket.onerror = function() {
console.log("onerror连接发生错误")
websocket_connected_count++;
if(websocket_connected_count <= 5){
newWebSocket()
}
}
// 接受到消息的回调方法
websocket.onmessage = function(e) {
console.log("接受到消息了")
heartCheck.reset().start(); // 如果获取到消息,说明连接是正常的,重置心跳检测
var message = e.data;
if(message){
//执行接收到消息的操作,一般是刷新UI
}
}
// 接受到服务端关闭连接时的回调方法
websocket.onclose = function() {
Tip("onclose断开连接");
}
// 监听窗口事件,当窗口关闭时,主动断开websocket连接,防止连接没断开就关闭窗口,server端报错
window.onbeforeunload = function() {
websocket.close();
}
// 心跳检测, 每隔一段时间检测连接状态,如果处于连接中,就向server端主动发送消息,来重置server端与客户端的最大连接时间,如果已经断开了,发起重连。
var heartCheck = {
timeout: 55000, // 9分钟发一次心跳,比server端设置的连接时间稍微小一点,在接近断开的情况下以通信的方式去重置连接时间。
serverTimeoutObj: null,
reset: function() {
clearInterval(this.serverTimeoutObj);
return this;
},
start: function() {
var self = this;
this.serverTimeoutObj = setInterval(function() {
if(websocket.readyState == 1){
console.log("连接状态,发送消息保持连接");
websocket.send("ping");
// heartCheck.reset().start(); // 如果获取到消息,说明连接是正常的,重置心跳检测
} else {
console.log("断开状态,尝试重连");
newWebSocket();
}
}, this.timeout)
}
}
}参考:https://nginx.org/en/docs/http/websocket.html
<< 上一篇
下一篇 >>
网友留言(1 条)