Nginx反向代理流式输出延迟?一招解决SSE/WebSocket缓冲问题
SpringBoot+SSE流式输出卡住?Nginx这个配置必须关!
Nginx代理后端流式响应要等好久才输出?完整解决方案来了
AI对话流式输出卡顿?Nginx proxy_buffering关闭指南
宝塔面板Nginx配置流式输出,90%的人都漏了这行配置
一、问题描述
最近在项目中使用 SpringBoot + SSE(Server-Sent Events) 实现流式输出功能(类似ChatGPT的打字机效果),发现前端接收数据时有明显延迟,需要等后端积累好多字才会输出一次,而不是实时逐字输出。
现象:
-
后端已经返回数据,但前端迟迟收不到
-
需要等待几秒甚至更久才一次性输出一大段
-
流式效果完全失效,用户体验极差
环境:
-
Nginx 反向代理
-
后端:SpringBoot
-
协议:SSE / 流式响应
二、问题原因
Nginx 作为反向代理时,默认会开启响应缓冲(proxy_buffering),它会等后端响应达到一定大小后,才一次性发送给客户端。这对于普通HTTP请求没问题,但对于流式输出就是灾难。
核心原因:
Nginx 默认缓冲 → 数据积累到缓冲区阈值 → 才发送给客户端
三、解决方案
3.1 关键配置
在 Nginx 的 location 块中添加以下配置:
location ^~ /jeecg-boot {
proxy_pass http://127.0.0.1:9191/jeecg-boot/;
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_set_header Upgrade $ http_upgrade;
proxy_set_header Connection "upgrade";
# ⭐ 流式输出核心配置 ⭐
proxy_buffering off; # 关闭代理缓冲(最重要!)
proxy_cache off; # 关闭缓存
proxy_request_buffering off; # 关闭请求缓冲
chunked_transfer_encoding on; # 启用分块传输
# 可选:设置较小的缓冲尺寸
proxy_buffer_size 1k;
proxy_buffers 4 1k;
proxy_busy_buffers_size 2k;
# 超时设置(防止长连接断开)
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
3.2 配置说明
| 配置项 | 作用 | 是否必须 |
|---|---|---|
proxy_buffering off |
关闭响应缓冲,实时转发 | ⭐ 必须 |
proxy_cache off |
关闭缓存 | 推荐 |
proxy_request_buffering off |
关闭请求缓冲 | 推荐 |
chunked_transfer_encoding on |
启用分块传输编码 | 推荐 |
proxy_read_timeout |
延长读取超时时间 | 长连接必须 |
四、后端配合配置
4.1 SpringBoot SSE 响应头
后端也需要设置正确的响应头,否则Nginx配置了也没用:
@GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> stream() {
return Flux.interval(Duration.ofMillis(100))
.map(sequence -> ServerSentEvent.builder("数据:" + sequence)
.build());
}
关键响应头:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
X-Accel-Buffering: no
4.2 普通流式响应
@GetMapping("/flow")
public void flow(HttpServletResponse response) throws IOException {
response.setContentType("text/plain;charset=utf-8");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Connection", "keep-alive");
response.setHeader("X-Accel-Buffering", "no"); // 关键!
ServletOutputStream out = response.getOutputStream();
for (int i = 0; i < 10; i++) {
out.write(("数据" + i + "\n").getBytes(StandardCharsets.UTF_8));
out.flush(); // 必须flush
Thread.sleep(100);
}
}
七、常见问题排查
7.1 配置后仍然有延迟?
- 检查是否有CDN:CDN也会缓冲,需要单独配置
- 检查Gzip:流式内容建议关闭gzip
- 检查后端是否flush :确保后端每次写入后都调用了
flush()
7.2 连接频繁断开?
增加超时时间,并检查防火墙设置:
proxy_send_timeout 600s;
proxy_read_timeout 600s;
keepalive_timeout 600s;
7.3 WebSocket也适用吗?
适用!WebSocket同样需要关闭缓冲,配置基本一致。
八、总结
表格
| 场景 | 关键配置 |
|---|---|
| SSE流式输出 | proxy_buffering off |
| WebSocket | proxy_buffering off + Upgrade头 |
| 大文件下载 | proxy_buffering off |
| AI对话流式 | proxy_buffering off + 后端flush |
核心就一行:proxy_buffering off;
但别忘了后端配合设置响应头和flush,否则还是不会实时输出!
九、参考资料
如果对你有帮助,欢迎点赞👍 收藏⭐ 关注💖
有问题欢迎在评论区留言讨论!