nginx 代理 websocket 二进制流需透传 upgrade/connection 头、关闭 proxy_buffering 和 gzip、调大 proxy_read_timeout/proxy_send_timeout 至 86400、启用 tcp_nodelay,并通过 wireshark 或字节比对验证帧无损透传。

要让 Nginx 代理 WebSocket 时二进制数据流(如 Uint8Array、图片分片、音频帧)无损透传,关键不是“支持二进制”,而是**阻止 Nginx 对原始字节流做任何干预**。Nginx 本身不解析帧内容,但默认缓冲、压缩、超时等行为会破坏帧边界、截断数据或引入延迟。
必须透传协议升级头,否则连接根本建不起来
WebSocket 握手失败,后续所有帧(无论文本还是二进制)都发不出去:
- proxy_http_version 1.1 —— HTTP/1.0 不支持 Upgrade,缺了直接 400
- proxy_set_header Upgrade $http_upgrade —— 用变量转发,兼容 websocket/mqtt/stomp 等多种升级协议
-
proxy_set_header Connection "upgrade" —— 注意是小写 upgrade、英文双引号;写成
$http_connection或"Upgrade"都会导致后端收不到升级信号
必须关闭缓冲与压缩,否则帧会被合并、截断或解码失败
只要开了 buffering 或 gzip,二进制帧就大概率出问题:粘包、长度错乱、服务端报 1009 或直接断连:
- proxy_buffering off —— 强制禁用响应缓冲,避免多个 BINARY 帧被攒在一起发送
- gzip off —— WebSocket 帧不可压缩,开启后服务端收到乱码,尤其传输 ArrayBuffer 时必崩
- proxy_buffer_size 4k —— 若某些模块强制要求设 buffer_size,只设最小值,且不启用多级缓冲
- proxy_set_header X-Accel-Buffering "no" —— 兼容部分 Nginx 版本,防止内部加速缓冲偷偷生效
必须调大超时并优化 TCP 行为,适配大帧和分片间隔
默认 60 秒超时对二进制流极不友好,上传模型权重、视频分片或网络抖动时极易中断:
- proxy_read_timeout 86400 —— 等待后端发数据的最长时间,覆盖空闲期或分片间等待
- proxy_send_timeout 86400 —— 向后端发送大帧时,避免未发完就被切断
- tcp_nodelay on —— 关闭 Nagle 算法,小帧(如鼠标坐标、心跳)立即发出,不凑包
- client_max_body_size 0 —— WebSocket 不走 HTTP body 流程,此项应禁用限制
验证是否真正无损,不能只看连接成功
101 响应只是握手完成,不代表帧内容没被改过:
- 前端发送
ws.send(new Uint8Array([0x01, 0xFF, 0x80])),检查后端收到的字节是否完全一致 - Wireshark 抓包过滤
websocket,确认 Frame Type 显示 BINARY,Payload Length 和原始匹配 - 若返回 400 或立即断连 → 优先查 Upgrade/Connection 头是否丢失;若长度错乱或截断 → 重点查
proxy_buffering和gzip是否残留











