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

Spring MVC中SSE异步API抛出IllegalStateException异常求助

问题分析与解决方案

核心代码错误

你的代码中存在SseEmitter实例不匹配的问题,这是引发后续异常的根本原因:

  1. 服务方法中创建了新的SseEmitter实例,但返回的是sseContext.getSseEmitter()而非刚创建的实例,导致控制器返回的Emitter与异步线程操作的Emitter不是同一个对象。
  2. 异步组件方法接收了sseEmitter参数,但实际操作的是sseContext.getSseEmitter(),进一步加剧了实例不匹配问题,导致响应状态处理混乱。

代码修正

1. 修正服务方法

@Override
public SseEmitter executeServiceStreaming(String command) {
    SseEmitter sseEmitter = new SseEmitter(15 * 60 * 1000L);
    // 若需存入上下文,确保存入当前创建的实例
    sseContext.setSseEmitter(sseEmitter);
    commandInvoker.invokeAsyncMethodStreaming(command, sseEmitter);
    return sseEmitter; // 返回当前创建的实例
}

2. 修正异步组件方法

@Async("cmdAsyncCall")
public void invokeAsyncMethodStreaming(String cliBuff, SseEmitter sseEmitter) {
    Socket sock = null;
    try {
        sock = connectionManagerFactory.getCommandExecConnection(cliBuff);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                // 按SSE规范发送数据
                sseEmitter.send(SseEmitter.event().data(line));
            }
            // 使用传入的Emitter完成响应
            sseEmitter.complete();
        }
    } catch (Exception e) {
        // 使用传入的Emitter处理错误
        sseEmitter.completeWithError(e);
        throw new CustomException(ErrorConstants.EC_SOCKET_READ_FAILED, e);
    } finally {
        // 确保Socket资源被关闭
        if (sock != null) {
            try {
                sock.close();
            } catch (IOException ignored) {}
        }
    }
}

Tomcat异常处理

修正代码后若仍出现Cannot call sendError() after the response has been committed异常,原因是Tomcat的Valve组件(如RequestFilterValve/RemoteAddrValve)在异步请求完成后,仍尝试对已提交的响应执行过滤操作:

解决方案:

  1. 检查Tomcat Valve配置:若不需要RemoteAddrValve等IP过滤Valve,直接移除相关配置;若必须保留,确保Valve仅在请求初始化阶段执行,而非异步dispatch阶段。
  2. 调整Tomcat日志级别:若确认该异常不影响业务功能(客户端已正常接收数据并关闭连接),可在logging.properties中将org.apache.catalina.valves.RequestFilterValve的日志级别设为WARNING或INFO,避免错误日志刷屏:
    org.apache.catalina.valves.RequestFilterValve.level = WARNING
    
  3. 验证异步支持配置:确保Spring MVC异步处理配置正确,控制器方法可添加@ResponseBody(返回SseEmitter时可省略,但明确配置更稳妥),同时确认Tomcat的asyncSupported属性已开启(Spring Boot默认已配置)。

SSE最佳实践

  • 发送数据遵循SSE规范,使用SseEmitter.event()构建事件,可指定id、event类型等字段提升兼容性。
  • 定期发送心跳事件(如空注释)避免连接超时:
    sseEmitter.send(SseEmitter.event().comment("heartbeat"));
    
  • 合理设置SseEmitter超时时间,避免资源闲置。

内容的提问来源于stack exchange,提问作者chetan madnaik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:04:53