哎我刚从工位那边倒了杯咖啡…手还烫着呢…我就顺嘴跟你说下我这两天在搞那个 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。

