文章目录
- 前言
- SseEmitter 简介
- 测试demo
- 注意点
- 异常一 ResponseBodyEmitter is already set complete
前言
最近做AI类的开发,看到各大AI模型的输出方式都是采取的一种EventStream
的方式实现。
不是通常的等接口处理完成后,一次性返回。
而是片段式的处理完成一个分片,就立马告知前端做出处理;后续处理出新的片段则再次发送给客户端。
在Spring
框架中就有一个类似的方式实现。SseEmitter
。
SseEmitter 简介
SseEmitter
是在Spring 4.2
开始引入的,使用的话需要注意版本,不过Springboot 2.X 是可以玩的。
测试demo
编写一段代码,循环返回给客户端。如下所示:
package cn.xj.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/sse/mitter")
public class SseMitterController {
@GetMapping(value = "/stream", produces = "text/event-stream")
public SseEmitter stream() {
// 设置默认超时时间 0L 表示无限
// 注意:这里的单位是 ms
SseEmitter sseEmitter = new SseEmitter(30000L);
// 最好不要阻塞主线程
Executors.newSingleThreadExecutor().execute(() -> {
try {
for (int i = 0; i < 10; i++) {
sseEmitter.send("这只是一个流式输出案例:" + i);
TimeUnit.SECONDS.sleep(1);
}
// 通知客户端消息发送完毕
sseEmitter.complete();
} catch (Exception e) {
e.printStackTrace();
sseEmitter.completeWithError(e);
}
});
return sseEmitter;
}
}
浏览器请求,打开控制台查看数据格式,如下所示:
注意点
异常一 ResponseBodyEmitter is already set complete
这种问题通常是 设置超时时间timeout
太小导致的。网上很多demo中说的这个单位是秒,但实际测试来看,单位应该是毫秒 ms
。