Nginx配置SSE和WebSocket代理的完整指南
在现代网站开发中,实时通信功能已经很常见了。无论是用SSE实现服务器向客户端推送消息,还是用WebSocket建立双向通信,当项目部署到线上环境时,Nginx配置不对经常导致"本地能运行,线上就失效"的问题。
SSE和WebSocket该选哪个?
SSE(服务器推送事件)
通信方向:服务器 → 客户端(单向)
基于HTTP/1.1协议
浏览器会自动重新连接
适合场景:实时通知、日志推送、股票行情
WebSocket
通信方向:双向通信
独立的协议,需要升级连接
需要自己处理重新连接
适合场景:在线聊天、协同编辑、网页游戏
简单建议:只需要服务器推送数据就用SSE,需要双向交互就用WebSocket。
Nginx详细配置说明
假设你的后端服务地址是:http://127.0.0.1:8000
前端访问路径约定:
普通请求:/
SSE接口:/sse/...
WebSocket:/ws/...
第一步:设置WebSocket连接升级映射
这个配置必须放在 http {} 块里面:
# 根据客户端请求判断是否需要升级连接
# 如果是WebSocket请求,Connection设为"upgrade"
# 普通HTTP请求就设为"close",避免误判为长连接
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缓冲!
# 默认开启时,Nginx会缓存整个响应,导致消息不能实时推送到客户端
proxy_buffering off;
# 关闭代理缓存(防止中间件缓存事件流)
proxy_cache off;
# 关闭gzip压缩(SSE不能压缩,否则浏览器无法解析)
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_transfer_encoding on;
# 可选:支持跨域访问
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;
# 处理跨域预检请求(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;
# 可选:传递认证头,如果需要身份验证
# 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配置,也可以这样写:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";常见问题排查
SSE连接不工作?
检查是否漏了 proxy_buffering off;
确认后端返回的Content-Type是 text/event-stream
确保设置了 gzip off;
如果是多层Nginx代理,每一层都要配置 proxy_buffering off;
WebSocket连接失败?
检查是否正确传递了Upgrade和Connection头:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;在浏览器开发者工具里查看WebSocket请求状态是不是HTTP 101(Nginx访问日志有时不准,以浏览器Network面板为准)
超时时间是否太短(默认60秒可能不够)→ 建议设为 proxy_read_timeout 3600s;
最简单的可用配置(调试推荐)
SSE最小配置:
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;
}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;
}实际应用示例
SSE后端代码示例(Node.js):
app.get('/sse/notifications', (req, res) => {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// 每秒发送一次消息
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ time: new Date().toISOString() })}\n\n`);
}, 1000);
// 客户端断开连接时清理
req.on('close', () => {
clearInterval(interval);
});
});WebSocket后端代码示例(Node.js):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
// 处理客户端消息
ws.send(`收到消息: ${message}`);
});
// 定时发送消息
setInterval(() => {
ws.send('服务器推送消息');
}, 5000);
});配置生效步骤
检查配置文件语法:
sudo nginx -t重新加载配置:
sudo nginx -s reload总结要点
SSE成功关键:proxy_buffering off; + gzip off; + 长超时(proxy_read_timeout)
WebSocket成功关键:正确传递Upgrade和Connection头 + proxy_http_version 1.1 + 长超时
配置修改后一定要重新加载Nginx
测试时先在简单配置上验证,再应用到复杂环境
记住这些配置要点,就能避免大多数SSE和WebSocket在Nginx代理下的连接问题。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!