Nginx服务
对非同源地址的nginx配置要求
http同端口访问http跳转https(497错误)
关于Nginx 的 location 匹配规则总结
Nginx+LUA+Redis实现token访问鉴权
Nginx推荐日志配置格式
Nginx正确代理 SSE 与 WebSocket
Nginx实现后端Server域名动态解析
Nginx反向代理跨域问题
浏览器报错ERR_CONTENT_LENGTH_MISMATCH
Nginx常见HTTP Code错误排查
使用acme.sh部署证书至Nginx
Nginx在普通用户下使用特权端口 (443端口)
Nginx配置自定义状态页
try_files和alias的组合使用
Nginx中301重定向导致端口丢失
本文档使用 MrDoc 发布
-
+
首页
Nginx正确代理 SSE 与 WebSocket
在现代 Web 应用中,实时通信已成标配。无论是使用 Server-Sent Events (SSE) 实现服务端单向推送,还是通过 WebSocket 建立双向通道,一旦部署到生产环境,Nginx 配置不当往往是导致"本地能跑、线上失效"的罪魁祸首。 ## 一、SSE vs WebSocket 对比 | 特性 | SSE(Server-Sent Events) | WebSocket | |------|--------------------------|-----------| | 通信方向 | 服务器 → 客户端(单向) | 双向全双工 | | 协议基础 | 基于 HTTP/1.1,MIME 类型为 text/event-stream | 独立协议,需通过 Upgrade: websocket 升级建立 | | 连接管理 | 浏览器自动重连 | 需应用层实现重连 | | 适用场景 | 实时通知、日志流、行情推送 | 聊天室、协同编辑、在线游戏 | >**推荐** >仅需推数据 → 用 SSE >需双向交互 → 用 WebSocket ## 二、Nginx 配置详解 假设后端服务地址:`http://127.0.0.1:8000` 前端路由约定: - 普通请求:`/` - SSE 接口:`/sse/...` - WebSocket:`/ws/...` ### 1) 全局定义 WS 升级映射 全局定义 WebSocket 升级映射(必须放在 http {} 块内) ```nginx # 根据客户端是否发送 Upgrade 头,动态设置 Connection 值 # 若是 WebSocket 请求($http_upgrade = "websocket"),则 Connection 设为 "upgrade" # 否则设为 "close",避免普通 HTTP 请求被误判为长连接 map $http_upgrade $connection_upgrade { default upgrade; # 默认:升级连接(用于 WebSocket) '' close; # 空值:关闭连接(用于普通 HTTP) } ``` >⚠️ 此 map 指令不能放在 server 或 location 中! ### 2) Server 块完整配置 ```nginx server { listen 80; server_name your-domain.com; # 替换为你的实际域名或 IP # ──────────────────────────────── # 普通 API 请求(无需特殊处理) # ──────────────────────────────── location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $http_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; } # ──────────────────────────────── # SSE 专用配置(关键!务必逐项检查) # ──────────────────────────────── location ~ ^/sse/ { # 转发到后端服务 proxy_pass http://127.0.0.1:8000; # 必须使用 HTTP/1.1(SSE 依赖长连接和分块传输) proxy_http_version 1.1; # 【核心】禁用 Nginx 缓冲! # 默认开启时,Nginx 会缓存整个响应体,导致事件流无法实时到达客户端 proxy_buffering off; # 禁用代理缓存(防止中间件缓存事件流) proxy_cache off; # 关闭 gzip 压缩(SSE 不兼容压缩,浏览器无法解析压缩后的 event stream) gzip off; # 清空 Connection 头,防止 Nginx 自动添加 "Connection: close" proxy_set_header Connection ''; # 设置足够长的超时时间(单位:秒) # 根据业务需求调整,例如 1 小时 = 3600 秒 proxy_read_timeout 3600s; # 等待后端发送数据的最大空闲时间 proxy_send_timeout 3600s; # 向客户端发送数据的超时 proxy_connect_timeout 3600s; # 与后端建立连接的超时 # 告诉上游代理(如 CDN、多层 Nginx)不要缓冲此响应 proxy_set_header X-Accel-Buffering no; # 启用分块传输编码(SSE 依赖 chunked encoding 逐块发送数据) chunked_transfer_encoding on; # 可选:CORS 支持(允许跨域访问) add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Origin,Authorization,Accept,X-Requested-With' always; # 处理 CORS 预检请求(OPTIONS) if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; # 预检结果缓存 20 天 add_header 'Content-Length' 0; return 204; # 返回空响应,立即结束 } } # ──────────────────────────────── # WebSocket 专用配置(核心是协议升级) # ──────────────────────────────── location ^~ /ws/ { proxy_pass http://127.0.0.1:8000; # 必须使用 HTTP/1.1 proxy_http_version 1.1; # 【核心】传递 WebSocket 升级头 # 将客户端的 Upgrade 和 Connection 头原样转发给后端 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; # 可选: 传递 Authorization 头部,如果需要身份验证 # proxy_set_header Authorization $http_authorization; # 常规代理头(用于获取真实 IP、协议等) proxy_set_header Host $http_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; # WebSocket 连接通常较长,但无需像 SSE 那么久 proxy_read_timeout 300s; # 5 分钟无消息自动断开(可按需调整) proxy_send_timeout 300s; proxy_connect_timeout 3600s; } } ``` 替代写法(不使用 map): ```nginx proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; ``` ## 三、高频问题排查清单 ### 1) SSE 连接不工作 - 检查 `proxy_buffering off;` 是否遗漏 - 确认后端返回 `Content-Type: text/event-stream` - 保证 `gzip off;` 已设置 - 多层 Nginx 代理时,每一层都要配置 `proxy_buffering off;` ### 2) WebSocket 连接失败 - 检查是否传递了 Upgrade 和 Connection 头: ```nginx proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1; ``` - 客户端开发者工具中查看 WebSocket 请求状态是否为 HTTP 101(Nginx access.log 有时不准确,以浏览器 Network 面板为准) - 超时时间是否过短(默认 60 秒,可能不够)→ 建议设为 `proxy_read_timeout 3600s;` ## 四、最小配置(调试) ### 1) SSE 配置 ```nginx location /sse { proxy_pass http://backend; proxy_buffering off; # 必须! proxy_cache off; gzip off; proxy_set_header Connection ''; proxy_http_version 1.1; proxy_read_timeout 3600s; } ``` ### 2) WebSocket 配置 ```nginx location /ws { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 300s; } ``` ## 总结 - **SSE 成败关键**:`proxy_buffering off;` + `gzip off;` + 长超时(`proxy_read_timeout`) - **WebSocket 成败关键**:正确透传 `Upgrade` 与 `Connection` 头 + `proxy_http_version 1.1` + 长超时 配置生效后需要重载 Nginx ```bash sudo nginx -t && sudo nginx -s reload ```
Nathan
2026年1月4日 08:50
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文件
Docx文件
分享
链接
类型
密码
更新密码