Nginx配置SSE和WebSocket代理的完整指南

更新日期: 2025-12-01 阅读: 29 标签: SSE

在现代网站开发中,实时通信功能已经很常见了。无论是用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);
});


配置生效步骤

  1. 检查配置文件语法

sudo nginx -t
  1. 重新加载配置:

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代理下的连接问题。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13242

前端实现AI对话:使用SSE技术提升实时交互体验

在现代前端开发中,AI智能对话功能越来越常见。实现这类功能时,关键是要让用户能够实时看到AI返回的内容,而不是等待全部生成完毕才显示。Server-Sent Events(SSE)技术为此提供了一种高效且易于实现的解决方案。

从 WebSocket 到 SSE:实时通信的轻量选择

在实时网络应用领域,WebSocket 一直被认为是首选方案。无论是聊天应用、在线游戏还是协同编辑工具,WebSocket 的强大双向通信能力都让它成为开发者的首选。

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!