在项目部署过程中,经常有利用Nginx将前后端代理到同一个地址的情况,但是当后端有Socket服务时,则需要一些额外的配置。
前置知识
在与WebSocket建立连接过程中,主要需要以下三个字段:
- Upgrade:必须为websocket,表示需要升级协议为 WebSocket 进行通讯
- Connection:必须为Upgrade,表示需要升级连接
- Sec-WebSocket-Key:必须为随机字符串,用于握手验证,服务器也会返回一个类似的字符串
解决方法
而Nginx的默认反代配置不支持代理WebSocket,如果需要代理则需要明确地添加Upgrade
和Connection
字段。
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# ...
location /websocket {
proxy_pass http://124.222.224.186:8800;
# important
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
其中map的语法表示,若HTTP请求头的upgrade
字段为空,则将connection_upgrade
变量设置为close,不为空则设置为upgrade。
注意:map语句只能写在http{}内,写在server{}内会报错
proxy_set_header表示向socket服务端传递的请求头,需要传递Upgrade
和Connection
字段。
其他写法
如果项目无法编辑到http{},在翻阅了map的相关语法后,其实也可以利用if达到类似的效果,由于nginx中没有if-else的语法,因此用is_matched
变量中转一下。
server {
# ...
set $is_matched 1;
if ($http_upgrade = '') {
set $is_matched 0;
set $connection_upgrade close;
}
if ($is_matched = 1) {
set $connection_upgrade upgrade;
}
location /websocket {
proxy_pass http://124.222.224.186:8800;
# important
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}