You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot使用SseEmitter分阶段返回PROCESSING与OK状态码的优化问题

问题根因分析
  • 核心逻辑顺序错误:SseEmitter需要先返回给Spring MVC框架建立SSE连接,再异步执行业务逻辑推送消息。原代码把业务阻塞逻辑和send操作都放在请求线程执行,全部处理完才返回emitter,完全不符合SSE的非阻塞设计。
  • @Async使用错误:直接加在接口方法上会导致整个方法异步执行,Spring MVC拿不到及时返回的SseEmitter实例,无法建立连接。
  • 缺少连接完成回调:处理完业务后没有调用emitter.complete()关闭连接,前端EventSource会触发超时自动重连,重复触发请求。
  • 自定义线程池未使用:定义的nonBlockingService线程池没有实际承载异步业务逻辑。
  • 缺少异常兜底:没有处理业务执行异常的场景,容易出现连接泄漏。
优化后代码

1. Controller层修改

@RestController
public class MainController {
    // 生产环境建议用ThreadPoolExecutor手动配置参数,避免OOM
    private ExecutorService nonBlockingService = Executors.newCachedThreadPool();

    @CrossOrigin
    @GetMapping("/sse")
    public SseEmitter handleSse() {
        // 超时时间设置为略大于最长业务执行时间即可,这里设为5秒适配3秒业务
        SseEmitter emitter = new SseEmitter(5000L);
        
        // 异步执行业务逻辑
        nonBlockingService.execute(() -> {
            try {
                // 推送处理中状态,用value()返回状态码数值,也可以直接传枚举返回字符串
                emitter.send(HttpStatus.PROCESSING.value());
                // 执行业务逻辑
                TestService.doSMG();
                // 推送处理完成状态
                emitter.send(HttpStatus.OK.value());
                // 主动关闭SSE连接
                emitter.complete();
            } catch (Exception e) {
                // 异常场景关闭连接,避免泄漏
                emitter.completeWithError(e);
            }
        });
        
        // 立即返回emitter建立SSE连接
        return emitter;
    }
}

2. 前端代码适配

<html>
<head>
<script>
var sse = new EventSource('http://localhost:8080/sse');
sse.onmessage = function (evt) {
    var el = document.getElementById('sse');
    const status = Number(evt.data);
    if(status === 102) {
        el.appendChild(document.createTextNode('服务处理中...'));
    } else if(status === 200) {
        el.appendChild(document.createTextNode('服务处理完成'));
        // 处理完成主动关闭连接,避免自动重连
        sse.close();
    }
    el.appendChild(document.createElement('br'));
};
// 异常兜底处理
sse.onerror = function(err) {
    console.error('连接异常:', err);
    sse.close();
};
</script>
</head>
<body>
<p id = "sse">
</p>
</body>
</html>
额外优化建议
  • 生产环境不要使用Executors.newCachedThreadPool(),手动构造ThreadPoolExecutor,指定核心线程数、最大线程数、队列长度、拒绝策略,避免请求量过高引发OOM。
  • 如果需要传递更复杂的业务信息,可以发送JSON格式的消息,前端接收后解析即可。

内容的提问来源于stack exchange,提问作者Nate Hiber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 22:06:05