1. nginx代理问题
1.1 nginx反代到nginx
问题: 使用域名可以访问,使用IP报404
解决: 在location段proxy_pass参数上面加上一行:
proxy_set_header Host xxx.com;
1.2 nginx反代到项目
问题: location匹配到规则之后,无法从一个完整的url跳到另一个完整的url
解决: 在nginx配置文件的http段添加一行参数:
underscores_in_headers on;
1.3. nginx反代配置错误页面
问题: 无法捕捉到proxy_pass后的状态码(4xx、5xx)进行处理
解决:
#在server中location段proxy_pass参数上面添加一行
proxy_intercept_errors on;
#在server中添加error_page匹配:
error_page 403 404 500 502 503 504 /error.html;
location = /error.html {
root html/serverError;
}
1.4 nginx反代到阿里云
问题: nginx反代proxy_pass到函数计算服务时,由于传入的header中host是前端域名,不是函数计算绑定的域名,而且会把upstream中server域名解析为IP,阿里云无法识别。
解决:
#在server中location段中修改proxy_set_header参数,手动设置header host,传入函数计算的域名
proxy_set_header Host xxx.com;
1.5 nginx支持websocket代理,并保持连接超过60s不中断
1.5.1 支持websocket代理
在location段添加:
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "Upgrade";
**原理:**关键部分在于HTTP的请求中多了如下头部:
Upgrade: websocket
Connection: Upgrade
这两个字段表示请求服务器升级协议为WebSocket。服务器处理完请求后,响应如下报文:
// 状态码为101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
1.5.2 保持连接超过60s不中断
利用nginx代理websocket的时候,发现客户端和服务器握手成功后,如果在60s时间内没有数据交互,连接就会自动断开,为了保持长连接,可以采取来两种方式.
第一种方式:
同样是在location段添加:
proxy_read_timeout 600s
proxy_send_timeout 600s
两个超时参数含义:
proxy_read_timeout语法:默认值 60s 上下文 http server location 说明 该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来获得请求的响应。 这个时间不是获得整个response的时间,而是两次reading操作的时间。
proxy_send_timeout语法:默认值 60s 上下文 http server location 说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操作期间。 如果超时后,upstream没有收到新的数据,nginx会关闭连接
如果在10分钟之内没有数据交互的话,websocket连接就会自动断开,所以这种方式还是有点问题,如果我页面停留时间超过十分钟而且又没有数据交互的话,连接还是会断开的,所以需要同时结合第二种方法.
第二种方式:
在nginx延长超时时间的基础上,前端在超时时间内发心跳包,刷新再读时间,前端具体实现见如下代码(此处代码包含了前端整个websocket的实现过程,其中加粗重点标注了发心跳包的内容):
// 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(){
clearTimeout(this.timeoutObj);
clearTimeout(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)
}
}
}