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

Spring MVC中SseEmitter调用curl出现transfer closed报错

解决SseEmitter使用中curl返回"transfer closed with outstanding read data remaining"的问题

我之前在做SSE相关的Spring MVC项目时,也碰到过一模一样的curl错误,咱们来拆解下你的代码问题:

问题根源分析

你的代码里有两个关键问题导致了这个错误:

  1. 线程池未正确关闭:用Executors.newSingleThreadExecutor()创建的线程池会持有非守护线程,如果不手动关闭,这些线程会一直存活,导致容器无法正常回收连接资源,当SSE完成后连接被强制中断,curl就会抛出"transfer closed with outstanding read data remaining"。
  2. SSE消息发送不够规范:直接用emitter.send()传字符串虽然能工作,但缺少SSE规范的消息结构,偶尔会导致客户端识别异常。

修复后的代码

@RequestMapping(path = "/finite/{count}", method = RequestMethod.GET)
public SseEmitter getFiniteMessages(@PathVariable int count){
    LOG.info("Request received for finite messages.");
    final SseEmitter emitter = new SseEmitter();
    
    // 创建带命名的线程池,同时设置线程为守护线程
    ExecutorService service = Executors.newSingleThreadExecutor(r -> {
        Thread workerThread = new Thread(r);
        workerThread.setName("SSE-Finite-Message-Worker");
        workerThread.setDaemon(true); // 守护线程不会阻止JVM退出
        return workerThread;
    });
    
    service.execute(() -> {
        try {
            for (int i = 0; i < count; i++) {
                // 用Spring推荐的SseEmitter.event()构建规范的SSE消息
                emitter.send(SseEmitter.event()
                        .data(LocalTime.now().toString(), MediaType.TEXT_PLAIN));
                Thread.sleep(200);
            }
            // 发送完成后正常结束Emitter
            emitter.complete();
        } catch (Exception e) {
            LOG.error("Error sending SSE messages", e);
            emitter.completeWithError(e);
        } finally {
            // 无论成功失败,都关闭线程池释放资源
            service.shutdown();
        }
    });
    
    // 添加超时处理,防止连接长时间闲置
    emitter.onTimeout(() -> {
        LOG.warn("SSE connection timed out");
        emitter.complete();
        service.shutdownNow();
    });
    
    return emitter;
}

关键修复点说明

  • 守护线程设置:把工作线程设为守护线程,避免线程池残留的非守护线程阻止应用正常关闭或资源回收。
  • 线程池手动关闭:在finally块中调用service.shutdown(),确保任务执行完毕后回收线程池,避免线程泄漏。
  • 规范SSE消息构建:使用SseEmitter.event()方法构建消息,符合Server-Sent Events的标准格式,减少客户端解析问题。
  • 超时处理:给Emitter添加超时回调,防止客户端异常断开后连接一直占用服务器资源。

测试建议

测试的时候可以给curl加上-N参数禁用缓冲,这样能实时看到每一条SSE消息:

curl -N -X GET http://localhost:8080/score/sse/finite/4

内容的提问来源于stack exchange,提问作者sorabh solanki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:50:34