SSE接口本地正常远程一次性返回所有数据问题求助
SSE接口本地正常、远程批量返回的问题排查与解决
问题描述
编写的SSE测试接口本地调用时每秒返回一条消息,但部署到远程云服务器后,接口会等待所有消息生成完毕一次性返回。
接口代码
后端SSE接口实现:
public SseEmitter testStream(String question) { SseEmitter emitter = new SseEmitter(); // 启动异步处理 new Thread(() -> { try { for (int i = 0; i < 10; i++) { // 生成事件数据 String eventData = "Event data " + i; // 创建Server-Sent Event对象 ServerSentEvent event = ServerSentEvent.builder() .event("message") .data(eventData) .build(); // 序列化事件并发送给客户端 String serializedEvent = JSON.toJSONString(event); emitter.send(serializedEvent); // 等待1秒后发送下一条事件 Thread.sleep(1000); } // 结束SSE流 emitter.complete(); } catch (Exception e) { emitter.completeWithError(e); } }).start(); return emitter; }
REST接口暴露:
@GetMapping(path="/test",produces = MediaType.TEXT_EVENT_STREAM_VALUE) SseEmitter testStream(@RequestParam(required = true) String question);
测试命令
# 本地测试 curl -X GET -H 'Content-Type: application/json' -N http://localhost:11014/ai/stream/chat/test\?question\=1 # 远程测试 curl -X GET -H 'Content-Type: application/json' -H 'x-request-id:1' -H 'x-access-token: eyJhbGciOiJIUzUx.balabala.sDM53g' -N https://ai.example.top/ai/stream/chat/test\?question\=1
请求链路
客户端用户→DNS→Nginx→Kubernetes Traefik→Kubernetes内的Spring Gateway→Kubernetes Service→Kubernetes Pod
已尝试的配置:
- 请求头添加
Cache-Control:no-cache - 响应头设置
text/event-stream、Cache-Control:no-cache、Connection:keep-alive - Nginx配置
proxy_cache_bypass $http_pragma
解决方案
问题核心是链路中各代理层的缓冲区/缓存机制拦截了实时推送,需逐个环节禁用缓冲:
1. Nginx配置调整
针对/ai/stream路径强制禁用代理缓冲,确保实时转发响应:
location ^~ /ai/stream { proxy_redirect off; 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_pass http://127.0.0.1:8000; # 禁用代理缓冲,实时转发每段响应 proxy_buffering off; # 完全禁用缓存 proxy_cache off; # 设置长连接超时,适配SSE长时间连接 proxy_read_timeout 3600; # 传递长连接相关头 proxy_set_header Connection ''; chunked_transfer_encoding off; }
说明:Nginx默认会缓冲后端响应,直到缓冲区满或响应结束才发送给客户端,proxy_buffering off强制实时推送每一段数据。
2. Kubernetes Traefik配置调整
通过Ingress注解禁用Traefik的响应缓冲:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ai-ingress annotations: # 禁用响应缓冲 traefik.ingress.kubernetes.io/response-buffering: "false" # 设置长连接超时 traefik.ingress.kubernetes.io/proxy-read-timeout: "3600" spec: rules: - host: ai.example.top http: paths: - path: /ai/stream pathType: Prefix backend: service: name: ai-service port: number: 80
3. Spring Gateway配置调整
在网关路由中禁用响应缓冲,并配置长连接:
spring: cloud: gateway: routes: - id: ai-stream-route uri: lb://ai-service predicates: - Path=/ai/stream/** filters: - DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_FIRST httpclient: # 禁用响应缓冲 response-timeout: 3600000 connect-timeout: 10000 pool: max-idle-time: 300000
也可通过自定义过滤器强制开启分块传输:
@Component public class DisableBufferingFilter implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { exchange.getResponse().getHeaders().set("Cache-Control", "no-cache, no-store, must-revalidate"); exchange.getResponse().getHeaders().set("Pragma", "no-cache"); exchange.getResponse().getHeaders().set("Expires", "0"); // 开启分块传输,禁用缓冲 exchange.getResponse().setChunked(true); return chain.filter(exchange); } }
4. 后端SSE接口优化
使用Spring提供的标准SSE发送方法,避免自定义序列化可能导致的格式问题:
// 替换原序列化代码,直接使用SseEmitter的事件构造器 emitter.send(SseEmitter.event() .name("message") .data(eventData));
说明:Spring会自动生成符合SSE规范的格式(包含event:、data:字段及换行分隔符),确保代理层正确识别分段响应。
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

