大数跨境
0
0

Spring 实现 3 种异步流式接口,干掉接口超时烦恼

Spring 实现 3 种异步流式接口,干掉接口超时烦恼 Java技术图谱
2025-12-05
0

哎我刚从工位那边倒了杯咖啡…手还烫着呢…我就顺嘴跟你说下我这两天在搞那个 Spring 的异步流式接口,真的,被接口超时折磨得头都大了…昨天晚上十一点多我们组那个小李凑过来跟我说“东哥你那个接口怎么老 30 秒就断啊”,我当时人都麻了…

我边拍他桌子边说:“别急别急…这事儿其实有 3 招,Spring 自带就能搞定…你别老靠同步返回那种笨办法…”

我就随便跟你说说啊,反正我现在脑子还有点晕,想到哪说哪…

(1)SSE:最轻的那种…像边说边推送的那种

我那天在公司楼下抽烟的时候突然想起来,SSE(Server-Sent Events)其实特适合那种“我慢慢返回,你别断我”的情况嘛,就单向推送,浏览器也支持得挺好。

我当时随手写了段代码,你要也看看:

@GetMapping(value = "/log/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter streamLog() throws IOException {
    SseEmitter emitter = new SseEmitter(0L); // 0:永不超时
    new Thread(() -> {
        try {
            for (int i = 0; i < 20; i++) {
                emitter.send("line-" + i);
                Thread.sleep(500);
            }
            emitter.complete();
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    }).start();
    return emitter;
}

我跟小李说:“你看吧,别怕慢,能一直推就不超时。” 他点头点得又快又狠。

不过这玩意儿吧…兼容性一般般,HTTP/1.1 长连接撑着…后端压力还行。

(2)ResponseBodyEmitter:比 SSE 多点自由度,像在往 OutputStream 慢慢灌

我记得前天凌晨在工位趴了一会儿,起来突然想到:我们那个耗时查询其实得返回 JSON,不适合 SSE 那种文本 event,那就用这个 ResponseBodyEmitter。

它特别适合“我算一点发一点”,也不用管整体超不超时。

代码我当时写成这样(有点乱,你将就看看):

@GetMapping("/export")
public ResponseBodyEmitter export() {
    ResponseBodyEmitter emitter = new ResponseBodyEmitter();
    new Thread(() -> {
        try {
            for (int i = 1; i <= 10; i++) {
                Map<String, Object> block = new HashMap<>();
                block.put("index", i);
                block.put("value""data-" + i);
                emitter.send(block);
                Thread.sleep(300);
            }
            emitter.complete();
        } catch (Exception e) {
            emitter.completeWithError(e);
        }
    }).start();
    return emitter;
}

你别问小李看到这段之后为什么笑…他说“像在边吃边吐”,我差点拿键盘甩他。

但这个方式确实解决了他的导出接口老是卡 30 秒超时的问题。

(3)Reactive WebFlux:最正宗的异步流(但坑多)

上周在公司茶水间,跟我们组那个老周聊到这个,他说他年轻的时候(其实没多年轻)就开始用 Reactor。WebFlux 这种就是真正的响应式,你想流式返回流式处理都没问题。

那天我边喝豆浆边写了个 demo:

@GetMapping(value = "/reactive/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> reactiveStream() {
    return Flux.interval(Duration.ofMillis(400))
            .map(i -> "msg-" + i)
            .take(20);
}

这个就是真·不会超时,因为它不是“处理完返回”,而是“你来我就继续推”。

不过吧,我跟你说实话:要整个项目都换成 WebFlux 才好用,不然你在 MVC 里掺一脚 WebFlux 那是真·折腾。

我当时看着小李那张快要哭出来的脸,直接给他三行建议:

  • 你要的是简单?用 SSE。
  • 你要返回 JSON?用 ResponseBodyEmitter。
  • 你要做整个链路都流式甚至高并发?上 WebFlux。

他听完直接说“东哥你早点讲我早下班了”。

我说“你别废话赶紧把昨天那个报错给我复现一下…哎算了算了我先去接个电话…”

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html


🔥东哥私藏精品🔥


东哥作为一名老码农,整理了全网最全《Java高级架构师资料合集》。总量高达650GB

【声明】内容源于网络
0
0
Java技术图谱
回复 java,领取Java面试题。分享AI编程,AI工具,Java教程,Java下载,Java技术栈,Java源码,Java课程,Java技术架构,Java基础教程,Java高级教程,idea教程,Java架构师,Java微服务架构。
内容 1111
粉丝 0
Java技术图谱 回复 java,领取Java面试题。分享AI编程,AI工具,Java教程,Java下载,Java技术栈,Java源码,Java课程,Java技术架构,Java基础教程,Java高级教程,idea教程,Java架构师,Java微服务架构。
总阅读62
粉丝0
内容1.1k