在现代Web应用中,实时通信已成标配。无论是使用Server-Sent Events(SSE) 实现服务端单向推送,还是通过WebSocket建立双向通道,一旦部署到生产环境,Nginx配置不当往往是导致“本地能跑、线上失效”的罪魁祸首。
一、SSE 与 WebSocket:核心区别与选型
| 特性 |
SSE (Server-Sent Events) |
WebSocket |
| 通信方向 |
服务器 → 客户端(单向) |
双向全双工 |
| 协议基础 |
基于 HTTP/1.1,MIME 类型为 text/event-stream |
独立协议,需通过 Upgrade: websocket 升级建立 |
| 连接管理 |
浏览器自动重连 |
需应用层实现重连 |
| 适用场景 |
实时通知、日志流、行情推送 |
聊天室、协同编辑、在线游戏 |
选型建议:如果只需服务器向客户端推送数据,选用SSE;若需客户端与服务器双向实时交互,则使用WebSocket。
二、Nginx 代理长连接配置详解(带注释)
假设后端服务运行在 http://127.0.0.1:8000,前端访问路径约定如下:
- 普通 API 请求:
/
- SSE 接口:
/sse/...
- WebSocket 接口:
/ws/...
第一步:全局 WebSocket 协议升级映射
此map指令必须放在 http {} 配置块内,用于动态设置Connection头部。
# 根据客户端是否发送 Upgrade 头,动态设置 Connection 值
# 若是 WebSocket 请求($http_upgrade = "websocket"),则 Connection 设为 "upgrade"
# 否则设为 "close",避免普通 HTTP 请求被误判为长连接
map $http_upgrade $connection_upgrade {
default upgrade; # 默认:升级连接(用于 WebSocket)
'' close; # 空值:关闭连接(用于普通 HTTP)
}
⚠️ 注意:map 指令不能放在 server 或 location 块中。

第二步:Server 块完整配置
以下配置包含逐行中文注释,清晰地展示了反向代理的核心要点。
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 缓冲与缓存
proxy_buffering off; # 必须!否则Nginx会缓存整个响应体,导致事件流不实时
proxy_cache off;
# 关闭 gzip 压缩(SSE 不兼容压缩,浏览器无法解析压缩后的 event stream)
gzip off;
# 清空 Connection 头,防止 Nginx 自动添加 "Connection: close"
proxy_set_header Connection '';
# 设置长超时时间(根据业务需求调整,例如1小时)
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;
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 升级头
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade; # 使用前面定义的 map 变量
# 常规代理头(用于获取真实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;
# 设置合理的超时时间
proxy_read_timeout 300s; # 5分钟无消息自动断开(可按需调整)
proxy_send_timeout 300s;
proxy_connect_timeout 3600s;
}
}
替代写法(不使用map指令):
如果你不想使用全局的map,可以在WebSocket的location块中直接写死Connection头。
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
三、高频问题排查清单
SSE 连接不工作?
- 检查缓冲:确认
proxy_buffering off; 是否已设置,这是SSE生效的关键。
- 检查响应头:确保后端返回正确的
Content-Type: text/event-stream。
- 检查压缩:确认
gzip off; 已设置。
- 多层代理:如果有多层Nginx或CDN,每一层都需要配置
proxy_buffering off;。
WebSocket 连接失败?
- 检查升级头:确认配置中正确传递了
Upgrade 和 Connection 头部,并使用了 proxy_http_version 1.1;。这是HTTP协议升级的基础。
- 检查状态码:在浏览器开发者工具的Network面板中,查看WebSocket握手请求的状态码是否为 101 Switching Protocols。Nginx的access.log有时记录不准确,应以浏览器为准。
- 检查超时:默认的
proxy_read_timeout 为60秒,对于长连接可能过短,建议适当延长。

四、最小可用配置(用于快速调试)
SSE 最小配置
location /sse {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_buffering off; # 必须!
proxy_cache off;
gzip off;
proxy_set_header Connection '';
proxy_read_timeout 3600s;
}
WebSocket 最小配置
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;
}
总结与核心要点
|