☰
Nginx WebSocket代理配置详解:从握手原理到生产实践
2026/10/9 12:32:15 网站建设 项目流程

1. WebSocket代理到底在解决什么问题

Nginx里配置WebSocket代理,这件事我踩过的坑比想象中多。很多时候,你只是想在现有Nginx反向代理上加一个实时通信接口,于是照着普通HTTP的配置写了proxy_pass,结果浏览器里WebSocket一直卡在握手阶段,后端日志里看不到连接,或者好不容易连上了,几十秒之后又自动断开。这篇文章就把Nginx配置WebSocket代理的完整逻辑、直接能用的配置、常见故障排查一次讲清楚。适合正在搭实时消息、在线协作编辑、行情推送、物联网长连接,或者只是在前后端分离项目里给/ws接口做统一入口的运维和开发者。

先说结论:Nginx本身对WebSocket的代理能力完全够用,但默认行为并不会帮你把“升级”请求处理好。你需要在配置里明确把Upgrade和Connection两个请求头透传下去,同时把超时时间从默认值调大。只要掌握了这几个关键点,Nginx做WebSocket代理真的不难。

1.1 一次握手是如何从普通HTTP“升级”成WebSocket的

WebSocket和普通HTTP最大的区别,是它没有“每次请求都重新建连”的套路。常规HTTP是一个请求对应一个响应,响应完连接基本就结束了;WebSocket则是先用HTTP协议发一个握手请求,请求头里带着Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Key、Sec-WebSocket-Version等信息。如果服务端愿意切换协议,会返回101 Switching Protocols,之后的连接就变成全双工的长连接,前后端可以随时互相推数据。

这里有个容易忽略的细节:Nginx作为中间代理,必须完整地参与这次握手。浏览器发给Nginx的握手请求是什么样,Nginx转发给后端的请求也得是什么样。尤其是Upgrade头和Connection头,它们不是普通业务请求头,而是告诉后端“我想切换协议”的开关。Nginx默认会把Connection设置成close,等于把开关直接关掉了,后端自然返回不了101。

1.2 为什么不能直接复用普通HTTP反代配置

普通HTTP反向代理配置里,你只需要关心Host、X-Real-IP、X-Forwarded-For这些头,最多再配一下缓存、超时、负载均衡。Nginx在普通HTTP场景下默认行为已经够用,甚至它会主动把连接回收,这对大量短连接是好事。

但WebSocket是长连接,而且握手阶段要求HTTP连接必须能升级。如果沿用普通配置,Nginx默认的proxy_http_version 1.0和proxy_set_header Connection close都会让握手失败。1.0版本的HTTP协议本身不支持Upgrade机制,而后端看到Connection: close也会认为这个连接用完就该关。这两个默认行为叠加起来,就是大家最常见的“WebSocket连不上”的原因。

你可以这么理解:浏览器想进一扇双向门,Nginx站在门口,却默认把浏览器递过来的门卡没收了,后端压根不知道你想切换通道。我们配置WebSocket代理,本质上就是让Nginx别做那个没收门卡的人。

1.3 什么样的情况下才需要专门配置

如果前端直接连后端WebSocket服务,例如浏览器直接访问ws://192.168.1.10:8080,那不需要Nginx参与。但实际生产环境几乎不会这么做,原因很实际:

  • 域名统一入口,不能让用户在地址栏里写IP和端口。
  • 需要TLS加密,浏览器页面是https://时,WebSocket也必须用wss://,证书终止通常放在Nginx。
  • 多个后端实例需要负载均衡,入口只能有一个。
  • 需要统一的访问日志、频率限制、来源校验、鉴权等安全能力。

只要有一个理由,WebSocket流量就会经过Nginx。既然要经过,你就不能把WebSocket当普通HTTP处理。下面我会把配置前必须想清楚的几个原理拆开讲,这些都是我在实际排查里反复验证过的东西。

2. 配置前必须想清楚的5个关键点

2.1 Upgrade与Connection这两个头到底做了什么

Upgrade: websocket意味着“我想把当前HTTP协议升级为WebSocket协议”。Connection: Upgrade是告诉对端“注意,本请求里有Upgrade头,请按升级流程处理”。这两个头在HTTP规范里都有明确定义,缺任何一个,服务端都可能直接忽略升级请求。

在Nginx配置里,你会看到类似这样的两行:

proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade;

$http_upgrade是Nginx内置变量,它会读取客户端请求头Upgrade的值。如果客户端发的是普通HTTP请求,这个变量为空;如果发的是WebSocket握手请求,这个变量就是websocket。通过proxy_set_header把变量值透传给后端,就能保证后端收到和你浏览器收到的一模一样的升级请求。

2.2 map指令为什么是WebSocket配置的灵魂

为什么要用map单独生成一个$connection_upgrade变量,而不是直接写死Connection: Upgrade?因为不是所有请求都想升级协议。普通HTTP请求如果也被后端看到Connection: Upgrade,虽然很多框架不会出问题,但严格来说是不规范、容易引起歧义的。

所以Nginx社区的标准做法是加一段map映射:

map $http_upgrade $connection_upgrade { default upgrade; '' close; }

意思很直白:请求头里有Upgrade时,$connection_upgrade就变成upgrade;请求头里没有Upgrade时,$connection_upgrade就变成close。这样同一个location既能代理普通HTTP,又能代理WebSocket,互不干扰。

这段map必须放在http{}块内,不能放在server{}或location{}里。很多人把map抄到server里,然后nginx -t直接报错,这种低级错误我见过不止一次。放在http块里,下面所有server都能共用。

2.3 proxy_http_version 1.1到底解决什么问题

WebSocket握手依赖HTTP/1.1的Upgrade机制,HTTP/1.0根本没有这个能力。Nginx默认向上游发HTTP/1.0请求,所以哪怕你把Upgrade头设置得再正确,后端也没有办法理解“升级”这个动作。

配置里必须有这一行:

proxy_http_version 1.1;

它不算WebSocket专用配置,反而更像是反向代理的通用升级项。很多老的Nginx配置模板里没有这行,加上之后WebSocket立刻就能握手成功。如果你在后端看到客户端发来的HTTP版本是1.0,基本就是这里漏了。

2.4 长连接超时参数不能只调一个

普通HTTP代理里的默认超时通常够用,因为一次请求几十毫秒就结束了。但WebSocket建立后,连接可能长时间空闲,比如用户在聊天页面挂了半小时一句话没说。这时候Nginx的proxy_read_timeout会发挥作用。

Nginx默认的proxy_read_timeout是60秒,意思是两次上游响应之间的最大间隔。对于WebSocket,如果连接空闲超过这个时间没有数据帧,Nginx就会主动断开连接。很多“连上后一会儿就自动断”的问题,不是后端代码写的不好,而是Nginx把空闲连接清掉了。

所以做WebSocket代理,至少要同时调整这几个超时:

proxy_connect_timeout 10s; proxy_send_timeout 3600s; proxy_read_timeout 3600s;

proxy_connect_timeout是建立上游连接的超时,握手机制决定它不适合太长;proxy_send_timeout和proxy_read_timeout分别控制发送和读取的空闲上限,对长连接来说通常按小时级别设置。不过要注意,超时设得越长,死连接占用的资源越久,所以最好配合心跳机制,这部分排查章节再说。

2.5 location匹配顺序会悄悄吃掉你的WebSocket请求

Nginx的location匹配顺序是一个经典大坑。你以为写了location /ws/,所有/ws/请求都会进来,但实际请求可能被另一个location抢先接收。

Nginx匹配规则大致是:精确匹配=优先级最高;然后是^~前缀匹配;接着是按书写顺序执行的正则~和~*;最后才是普通前缀匹配的最长匹配。如果你的配置里先有一个location ~ \.(js|css|png)$,它不会影响/ws/,但如果有人写了一个宽松的正则,比如location ~ ^/api,而WebSocket地址是/api/ws,请求就会被正则location截走。

排查这种问题最直接的办法是把配置从头看一遍,确认WebSocket的location没有被更优先的location覆盖。还有一个更隐蔽的情况:location /ws和location /ws/不是一回事。前者能匹配/ws、/wsabc,后者只能匹配以/ws/开头的路径。如果后端接受的是/ws/,前端却连的是/ws,Nginx可能匹配成功,但代理路径和你预期的不一样。

3. 从单站点到多站点,可直接抄的Nginx配置

3.1 最简配置:单站点反代一个WebSocket服务

先把最常用的完整配置放出来,你可以直接复制修改:

map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream ws_backend { server 127.0.0.1:8080; } server { listen 80; server_name ws.example.com; location /ws/ { proxy_pass http://ws_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol; proxy_connect_timeout 10s; proxy_send_timeout 3600s; proxy_read_timeout 3600s; } }

这个配置里,location /ws/会把浏览器请求转发给127.0.0.1:8080。proxy_pass后面没有加URI,也就是说浏览器请求/ws/chat,转发给后端也是/ws/chat,路径保持不变。这个行为对WebSocket特别重要,很多后端路由就是靠路径区分不同房间或不同业务的,路径一旦被修改,握手都可能失败。

Sec-WebSocket-Protocol那行是用于WebSocket子协议协商的。如果你的客户端在握手时带了Sec-WebSocket-Protocol,比如请求里声明要用某个子协议,那么这行会把这个头原样传给后端。如果后端做了子协议校验,这个头就不能丢。Nginx默认不会主动丢弃它,但显式写出来更保险,也方便排查。

3.2 路径处理:请求怎么到后端才不丢

很多项目的对外WebSocket路径和后端真实路径不一样。比如前端连的是/ws/chat,后端服务只监听根路径/,Nginx如果不做任何处理,转发过去就是/ws/chat,后端找不到对应路由。

处理方式要看你想保留什么。如果后端就是希望接收/ws/chat,你什么都不用改,proxy_pass http://ws_backend;就够了。

如果要去掉/ws前缀,有几种写法:

location /ws/ { rewrite ^/ws/(.*)$ /$1 break; proxy_pass http://ws_backend; }

这里用rewrite把/ws/chat改写成/chat,break告诉Nginx改完路径后不要跳到其他location,继续用当前的proxy_pass转发。这个写法的好处是即使后端URI比较复杂,你也能精确控制最终转发路径。

还有一种常见写法是直接在proxy_pass后面加斜杠:

location /ws/ { proxy_pass http://ws_backend/; }

这段配置的效果是,proxy_pass里的URI是/,Nginx会把location匹配部分的/ws/替换成/,所以/ws/chat会变成/chat。这个写法的行为更隐晦,我自己更倾向用rewrite,因为一眼能看出来路径是怎么变的,排查时不用在脑子里模拟Nginx的路径替换规则。

3.3 多站点多域名:用conf.d组织配置更省心

一台Nginx上跑多个WebSocket服务是很常见的需求。比如一个项目有聊天服务,端口8080;另一个项目有实时通知,端口8082;甚至同一个域名下不同路径代理到不同后端。

推荐的做法是把每个站点的server配置单独放到/etc/nginx/conf.d/,或者如果你用的是云服务器管理面板、1Panel这类工具,就在面板里为每个站点单独创建反向代理,再在高级配置里补上WebSocket相关头部。

比如chat.conf:

server { listen 80; server_name chat.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }

另一个notify.conf:

server { listen 80; server_name notify.example.com; location /socket/ { proxy_pass http://127.0.0.1:8082; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; } }

只要第一段map在http级别定义了,多个server都能引用$connection_upgrade变量,不用担心冲突。多站点场景里最容易犯的错是每份配置各写了一份map,这样不是因为变量重复导致报错,就是因为位置不对导致nginx -t失败。正确做法是公共的map只写一次。

3.4 WSS加密:和HTTPS共存但证书别搞错

浏览器页面如果是https://,WebSocket地址就必须是wss://,否则浏览器会因为混合内容直接拦截。在Nginx上做WSS非常简单,就是把TLS证书终止在Nginx,再反向代理到后端普通的ws://服务。

一个完整的WSS配置长这样:

server { listen 443 ssl; server_name ws.example.com; ssl_certificate /etc/nginx/cert/fullchain.pem; ssl_certificate_key /etc/nginx/cert/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; location /ws/ { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Forwarded-Proto $scheme; } }

这时客户端连接地址是wss://ws.example.com/ws,Nginx卸载TLS后,把握手请求以普通ws://转发给127.0.0.1:8080。后端可以完全不知道证书存在,这是最常见的架构。

这里要特别提醒证书和域名的关系。很多人配完WSS以后,浏览器报ERR_CERT_COMMON_NAME_INVALID,原因是证书里的域名和访问域名对不上,或者证书不支持SAN扩展。Nginx配置里server_name必须和证书的CN或者SAN匹配。你在申请证书时,一定要确认把ws.example.com也加进去,尤其是多域名证书,漏一个子域名就会报这个错。

3.5 多个后端节点:WebSocket负载均衡的取舍

WebSocket是长连接,负载均衡要比普通HTTP更小心。普通HTTP每个请求独立,轮询就行;WebSocket一旦握手成功,后续所有数据都在同一条连接上传输,如果这一条连接中途被Nginx转发到另一台后端,客户端身份、会话状态就全乱了。

最简单的做法是用ip_hash:

upstream ws_backend { ip_hash; server 192.168.1.10:8080; server 192.168.1.11:8080; }

ip_hash会保证同一个客户端IP的请求总是落到同一台后端。缺点是如果大量用户来自同一个出口IP,比如公司内网、学校NAT,流量可能集中到一台后端。

另一种思路是用业务参数做一致性哈希,比如WebSocket连接URL里带roomId或userId:

upstream ws_backend { hash $arg_roomId consistent; server 192.168.1.10:8080; server 192.168.1.11:8080; }

hash指令是Nginx自带模块支持的,consistent让哈希分布更平滑。这个方法能让同一房间或同一用户的连接稳定落在同一台后端,比ip_hash更灵活。但前提是URL参数必须稳定,如果前端连接时随机生成连接ID,那哈希就没有意义。

更稳妥的做法是让后端本身无状态,所有连接上下文通过Redis或消息队列共享。这样就算客户端断线重连到了另一台节点,业务也能无缝接管。我的建议是:单机够用就别急着上集群,上集群后优先解决会话共享,最后才考虑用Nginx的哈希策略兜底。

4. 常见故障与排查实录

4.1 连接一直卡在101之前,先查Upgrade和Connection头

WebSocket握手成功后,浏览器Network面板里状态码应该是101 Switching Protocols。如果一直卡在Pending,或者显示Could not open WebSocket,首先检查Nginx配置里有没有这几行:

proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade;

然后检查map是不是放在http块里了。这个配置组合是WebSocket代理的基础三件套,缺任何一个都可能导致握手失败。

你还可以用命令直接验证Nginx转发行为:

curl -i -X GET http://127.0.0.1/ws \ -H "Connection: Upgrade" \ -H "Upgrade: websocket" \ -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \ -H "Sec-WebSocket-Version: 13"

如果后端配置正确,你会看到HTTP/1.1 101 Switching Protocols。如果看到400 Bad Request,多半是Connection头或者HTTP版本不对;如果看到404,那就是路径问题或者location匹配问题。

4.2 返回404 not found,location和后端路径一起查

Nginx的404分两种,一种是Nginx自己返回的,一种是后端返回的。先看Nginx日志里的upstream_addr和upstream_status,如果有upstream信息,说明请求已经转发到后端,404是后端路由没匹配;如果没有upstream信息,说明请求根本没进到对应的location,可能是location路径写错,或者被其他location截走了。

检查几个点:

  • 前端连接的路径是/ws/,location是不是只写了/ws,导致路径不匹配。
  • 有没有更优先的正则location抢先拦截。
  • proxy_pass是否带了URI,导致转发的路径被改掉了。
  • 如果没有匹配location,Nginx可能会落到server里的静态文件root,然后返回默认404页面。这时你要确认WebSocket站点里没有多余的location /把流量引到静态目录。

4.3 返回502 Bad Gateway,upstream没通

502说明Nginx已经准备转发,但连接不上后端。先确认后端服务是否启动,监听端口是否正确。我经常能看到这样的情况:后端明明在监听[::]:8080,Nginx用127.0.0.1:8080访问却失败。这时用curl http://127.0.0.1:8080/直接测一下最有效。

如果端口通,再看防火墙或云安全组是否放行Nginx所在机器访问后端端口。容器环境下,还要确认Nginx容器和后端容器是否在同一个网络里,127.0.0.1在容器里很可能只指向容器自己。

还有一个容易忽略的点:proxy_pass用的是域名,但Nginx容器里没有DNS解析能力,导致解析失败。这种情况直接用IP而不是域名,或者在http块里配置resolver。

4.4 连上后总被断开,超时和心跳一起调

如果你的WebSocket能握手成功,但过一段时间就被断开,先看断开的时机。如果差不多在60秒左右,基本就是proxy_read_timeout默认值的问题,把超时调大再看。

如果已经调大到3600秒还是断,就要考虑业务层的心跳机制。WebSocket有专门的控制帧Ping和Pong,服务端和客户端都可以主动发起。一个简单实用的方案是客户端每隔一段时间发一个Ping帧,服务端收到后返回Pong,这样连接里一直有数据在流动,Nginx就不会因为“空闲”断开连接。

前端大致是这个逻辑:

const ws = new WebSocket('wss://ws.example.com/ws'); ws.onopen = function () { setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send('ping'); } }, 20000); };

这里的间隔要小于Nginx的proxy_read_timeout,比如Nginx设60秒,心跳间隔设20秒,这样就有足够的余量扛住偶发网络抖动。后端也要对消息做判断,如果收到的是心跳内容,就不要当作业务消息处理,特别是有服务端推送逻辑的场景,避免把心跳误推给其他客户端。

4.5 证书或鉴权错误,不是Nginx代理的问题但经常误判

WSS配置好后,如果浏览器报证书错误,先确认你访问的域名和证书是否匹配。ERR_CERT_COMMON_NAME_INVALID这类问题,再调Nginx配置也解决不了,必须换证书,或者在申请证书时把域名加上。

如果接口需要鉴权,比如在WebSocket握手请求头里带Authorization或者Sec-WebSocket-Protocol,后端拿不到对应值的时候,可能直接返回403或400。Nginx通常会把请求头原样转发,但如果你在location里使用了proxy_set_header覆盖了一些头,要确认没有把鉴权头改掉。需要透传时,可以显式加上:

proxy_set_header Authorization $http_authorization;

另外,有些WebSocket库允许在URL查询参数里带token,比如/ws?token=abc。这种情况下proxy_pass如果不带URI,默认会保留查询字符串;如果你在后端做了重定向,要留意查询参数是否还会跟着走。

4.6 登录日志,比猜配置更高效

排查WebSocket代理问题,最忌讳的是反复改配置重启Nginx然后凭感觉猜。我现在的习惯是,先开启WebSocket站点的独立访问日志,然后在请求失败时立刻看一眼日志。

可以用一个单独的log_format,把协议特征也打出来:

log_format ws '$remote_addr [$time_local] "$request" $status ' '$http_upgrade "$upstream_addr" ' '$upstream_status $request_time';

然后在WebSocket站点里单独指定日志文件:

access_log /var/log/nginx/ws_access.log ws;

这样每个握手请求都会记录下$http_upgrade是否为websocket、上游地址和上游状态码。只要看一眼日志,就能确定问题出在Nginx还是后端。用这种方法,绝大多数WebSocket代理问题都能在一分钟内定位。

5. 生产环境里几个容易被忽视的细节

5.1 别忽略文件描述符和连接数限制

WebSocket连接不是普通HTTP那样用完就断,每条连接会占用一个文件描述符。当连接数涨到几千、几万时,Nginx worker进程的打开文件数限制会先被触顶。

在Nginx主配置里加上:

worker_rlimit_nofile 65535;

同时检查系统层面的ulimit -n限制。如果你的系统用的是systemd管理Nginx,还需要检查/etc/systemd/system/nginx.service里的LimitNOFILE,只改Nginx配置但系统不放开,照样会到上限。

如果是因为单IP连接数过多导致的问题,可以在location里加连接数限制:

limit_conn_zone $binary_remote_addr zone=perip:10m; location /ws/ { limit_conn perip 100; ... }

这条限制对IP连接数量超多的场景很实用,但要注意走NAT出口的用户会被当成同一个IP算,阈值要结合业务设置。

5.2 reload不会立刻中断长连接,但配置要考虑新旧worker

很多人在配置变更后会执行nginx -s reload,担心所有WebSocket长连接会被一次性断开。实际上Nginx会保留旧worker进程继续处理已经建立的连接,新请求才会进入新配置。所以普通reload对长连接相对友好,不会秒断所有连接。

但你要明白一件事:reload之后,已经建立的WebSocket连接仍然由旧配置、旧worker进程维护,如果连接一直不断,旧worker进程就会一直占用资源。如果某个location已经被删掉或改名,旧连接可能不会被释放,直到客户端主动断开或超时。

所以在生产环境做配置变更时,最好选择业务低峰期,并且观察一下worker进程数量变化。如果旧worker长期不退出,可以考虑主动重启Nginx,但那样所有长连接都会断,需要客户端有重连机制。

5.3 用独立日志和监控掌握WebSocket连接质量

我建议把WebSocket站点的日志和普通HTTP站点分开,不要混在一个access.log里。长连接场景下,请求频率不高,但连接数、断开原因才是更值得关注的指标。除了上一条提到的访问日志外,可以定期执行:

ss -tn state established '( dport = :443 or sport = :443 )' | wc -l

这个命令虽然粗糙,但能快速看到当前Nginx上的连接规模。更灵活的做法是用Prometheus的nginx_connections_accepted、nginx_connections_active等metrics建一个面板,再配合WebSocket业务层的连接数、消息量、心跳发送量,基本覆盖了运行状况。

日志里还有一个细节:WebSocket握手成功后会一直保持连接,Nginx不会在每次数据传输时都写access日志,所以你不要用请求量去判断连接是否活跃,要看业务心跳日志或上游连接统计。

5.4 配置片段复用,少写重复头部

每个server里的WebSocket相关头都一样,逐份复制容易漏。推荐把公共配置抽成snippet文件,例如/etc/nginx/snippets/websocket.conf:

proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 3600s; proxy_send_timeout 3600s;

然后在location里直接include:

location /ws/ { include snippets/websocket.conf; proxy_pass http://ws_backend; }

这样新站点接入WebSocket代理时,只需要写路径和upstream,不容易漏掉关键头。我自己维护的服务器上,所有反代配置都遵循这个模式,排查问题时不用一个头一个头去对比。

5.5 安全小建议:校验Origin和限制连接数

最后想提一下安全。WebSocket本身没有同源限制,恶意网页可以通过脚本去连接你的服务端,所以生产环境一定要校验Origin。可以在Nginx里拒绝非预期来源:

if ($http_origin !~ '^https?://(chat\.example\.com|example\.com)') { return 403; }

当然这只是入口层的一层过滤,真正的鉴权还是要在后端做,比如检查token、session是否有效。Nginx层的校验是用来挡绝大多数误连和恶意扫描的,不用写太复杂。

另外一个细节是,如果WebSocket握手请求里带了Sec-WebSocket-Protocol,后端必须对子协议做白名单校验。不要盲信任意子协议,防止客户端通过子协议头尝试一些非预期行为。

组合完这些手段以后,Nginx上的WebSocket代理基本就算是可靠了。我个人的习惯是每上线一个WebSocket站点,先手工用curl验证握手,再通过浏览器连一次,最后看访问日志里的$http_upgrade和$upstream_status。这两个地方正常,剩下的就交给心跳和监控去保障。多踩几次坑之后你会发现,Nginx配置本身并不复杂,复杂的是你愿不愿意耐心把原理、配置、日志串起来理解。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询