记一次 Nginx 反向代理 SSE(MCP)卡住的排查与解决

2026-03-03 118点热度 0人点赞 0条评论

背景

  • 服务:Spring AI MCP Server,SSE 端点 /sse,消息端点 /mcp/message

  • 环境:AWS EC2,Nginx 反代到本地 8049 端口

  • 现象:

    • 本机直连:curl -N -H "Accept: text/event-stream" http://localhost:8049/sse 正常

    • 外部访问:curl -N -H "Accept: text/event-stream" https://ai.example.com/sse 连接建立后一直“卡住”,无事件推送

问题原因定位

SSE 依赖长连接、流式输出,常被代理缓冲或压缩导致卡住。排查要点:

  1. 代理层是否开启了响应缓冲/缓存

  2. 是否强制压缩(gzip 等)

  3. 转发协议是否保持 HTTP/1.1(HTTP/1.0 会断流)

  4. 是否有路径前缀被重写(本例已去掉 /some-api 前缀)

最终解决方案(Nginx 配置)

对 /sse 单独关闭缓冲、缓存和压缩,明确使用 HTTP/1.1,延长超时:

server {
    listen 443 ssl;
    server_name ai.example.com;
    # ssl 证书配置略

    # 其他接口的通用转发
    location / {
        proxy_pass http://127.0.0.1:8049;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_read_timeout 1800s;
        proxy_send_timeout 1800s;
    }

    # SSE 专用:必须关闭缓冲/压缩
    location /sse {
        proxy_pass http://127.0.0.1:8049;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_buffering off;          # 关键:关闭缓冲
        proxy_cache off;
        proxy_request_buffering off;
        add_header X-Accel-Buffering no;
        add_header Cache-Control "no-cache";

        gzip off;                     # SSE 不要压缩
        proxy_read_timeout 1h;        # 长连接
        proxy_send_timeout 1h;
        chunked_transfer_encoding on;
    }
}

部署后执行:

nginx -t && nginx -s reload

验证步骤

  1. 外网测试(带 verbose 查看握手与头部):

    curl -v -N -H "Accept: text/event-stream" https://ai.example.com/sse

    正常时会持续挂起并收到 id:/event: 流。

  2. 若前面还有 CDN/ALB:

    • 关闭缓存/压缩

    • 确保转发使用 HTTP/1.1,不要降级到 1.0

  3. 若前端有跨域需求,可在 /sse 加:

    add_header Access-Control-Allow-Origin "*" always;

经验总结

  • SSE 要求“不断流、不过缓冲、不过压缩”,Nginx 默认缓冲/压缩会导致“连上不出数据”。

  • 明确 proxy_http_version 1.1 和 Connection "",避免被强制短连接。

  • 将 SSE 路径单独配置是一种简单且安全的做法,避免影响其他接口。

 

admin

这个人很懒,什么都没留下

文章评论

您需要 登录 之后才可以评论