本文由 简悦 SimpRead 转码, 原文地址 blog.csdn.net
这篇文章,主要介绍如何通过 Nginx 服务器转发客户端的 WebSocket 接口到后端服务【知识星球】。
目录
一、Nginx 配置 WebSocket
今天在工作中,遇到了一个需求,这个需求大概是前端和后端需要采用 WebSocket 方式来进行通信,因为是 WebSocket 接口,客户端需要知道通讯的接口地址,WebSocket 接口的地址格式是:【ws://ip:port/xxx/yyy】,其中 ip 和 port 是后端服务提供的,/xxx/yyy 是后端服务中提供的具体 WebSocket 接口地址。
这里就遇到了一个问题,后端服务不止一台,有可能启动两台服务,采用不同的端口来区分,客户端就不知道应该填写哪个 port 端口,后面想到的解决方案是通过 Nginx 服务器进行 WebSocket 接口的转发,让 Nginx 来决定调用哪个 WebSocket 接口,而客户端只需要和 Nginx 服务器进行交互即可。
案例下载地址:【https://download.csdn.net/download/qq_39826207/88883292】
1.1、Nginx 配置内容
为了让 Nginx 能够代理转发 WebSocket 接口,我们需要针对 WebSocket 接口地址配置一个 location 信息,使用 proxy_pass 转发到具体的后端接口服务。在 nginx.conf 配置文件中,添加如下配置内容:
#user nobody;
worker_processes 1;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
#gzip on;
keepalive_timeout 65;
# 定义变量,兼容HTTP和WebSocket两种请求协议
map $http_upgrade $connection_upgrade {
default keep-alive; # 默认 keep-alive,表示HTTP协议。
'websocket' upgrade; # 若是 websocket 请求,则升级协议 upgrade。
}
server {
listen 9990;
# 这里写后端接口服务提供的WebSocket完整地址
# 例如:我这里提供的WebSocket接口地址是 /demo/websocket
location /demo/websocket {
proxy_pass http://127.0.0.1:8880; # 转发到后端接口
proxy_read_timeout 20s; # 设置超时时间,默认是60s
proxy_http_version 1.1;
proxy_set_header Host $host; # 这个配置不要漏了,必须要
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
注意:上面配置中,有两个内容需要配置,见下图中的红色框框内容:

1.2、客户端请求地址
浏览器客户端向【ws://127.0.0.1:9990/demo/websocket】建立连接,当 Nginx 服务器接收到之后,就会匹配上 location 的定义的规则,此时会将【ws://127.0.0.1:9990/demo/websocket】地址转发到【ws://127.0.0.1:8880/demo/websocket】这个地址,这就完成了 WebSocket 接口的转发功能。
- 注意点:location 后面定义的地址要和后端接口提供的 WebSocket 地址一模一样,不能采用模糊匹配,否则转发不了 WebSocket 接口。
刚开始我是参考网上的一些配置,location 后面之间使用的【/websocket】,发现怎么也转发不了,后面测试了才知道,网上那些配置,他们对应后端 WebSocket 接口地址就是【/websocket】,所以他们可以转发成功。我的后端接口地址是【/demo/websocket】,location 配置成【/websocket】肯定是不行的。
1.3、创建 WebSocket 测试工程
为了模拟 Nginx 能否成功转发 WebSocket 接口,这里我本地创建了一个 WebSocket 的测试工程,如下所示:

1.4、启动测试
- 第一步:启动本地的 WebSocket 测试工程。
- 第二步:启动 Nginx 服务。
- 第三步:找一个在线的 WebSocket 测试工具,查看【ws://127.0.0.1:9990/demo/websocket】是否可以连接成功。
这里我使用的是【https://wstool.js.org/】WebSocket 在线测试工具,如下图所示:

从上图中,我们可以知道,WebSocket 接口服务对外提供的是 8880 端口,客户端连接的是 9990 端口,端口不一致的情况下,WebSocket 依然连接成功了,这说明我们配置的 Nginx 转发功能成功啦。
1.5、WebSocket 超时问题
Nginx 配置里面,默认情况下,WebSocket 接口的超时时间是 60s,如果在 60s 里面,都没有使用 WebSocket 进行发送消息,那么此时就会断开 WebSocket 连接。
这种情况下,我们客户端如果再次发送消息,就会抛出异常,因为 WebSocket 连接已经断开,无法发送消息,那么要如何解决这个问题呢???
针对上面的问题,可以有下面两种解决方案:
1.5.1、设置超时时间
Nginx 提供了一个【proxy_read_timeout】属性,该属性可以用于设置 WebSocket 接口的超时时间,默认是 60s,那么我们就可以设置成 5 分钟,配置内容如下所示:
# 这里写后端接口服务提供的WebSocket完整地址
# 例如:我这里提供的WebSocket接口地址是 /demo/websocket
location /demo/websocket {
proxy_pass http://127.0.0.1:8880; # 转发到后端接口
proxy_read_timeout 300s; # 设置超时时间,默认是60s
proxy_http_version 1.1;
proxy_set_header Host $host; # 这个配置不要漏了,必须要
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
注意:这种配置不推荐使用,因为 proxy_read_timeout 属性治标不治本,超过 5 分钟还是没有通信怎么办呢???不依然会断开连接吗。
1.5.2、建立心跳机制(推荐)
最好的机制是让客户端和服务器之间,每隔一段时间进行一次心跳通信,例如:让客户端每隔 30s 向服务器发送一次消息,客户端有发送消息给服务端,那么 Nginx 就知道当前这个 WebSocket 连接是有用的,就不会将其断开。
注意:假设超时时间是 60s,经过 30s 没有通信,按理说,再过 30s 没有通信,就会断开连接,但是如果客户端发送一条消息给服务端,此时,超时时间就会重新计算,超时时间又会变成 60s。
到此,Nginx 服务器转发 WebSocket 接口就配置完成啦。
综上,这篇文章结束了,主要介绍如何通过 Nginx 服务器转发客户端的 WebSocket 接口到后端服务。