是什么
SSE是Server-Sent Events的缩写。它是一种浏览器的技术,允许网站推送实时更新到浏览器,而无需浏览器发送请求。这种技术通常用于实现实时数据更新,例如新闻滚动条或社交媒体时间线。它可以帮助网站提供更加交互式和实时的体验。
发送的是消息流,也就是说一个连接被长时间的占用;一旦浏览器请求了一个接口,那么服务器就会主动向浏览器端发送信息。
只要浏览器支持,就可以使用。
优点
和WebSocket做对比。
- SSE 使用 HTTP 协议,现有的服务器软件都支持。WebSocket 是一个独立协议。
- SSE 属于轻量级,使用简单;WebSocket 协议相对复杂。
- SSE 默认支持断线重连,WebSocket 需要自己实现。
- SSE 一般只用来传送文本,二进制数据需要编码后传送,WebSocket 默认支持传送二进制数据。
- SSE 支持自定义发送的消息类型。
实现
数据格式
http的请求头是
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
java API
1、在@RequestMapping中指定参数
produces = MediaType.TEXT_EVENT_STREAM_VALUE
2、创建一个SseEmitter,
SseEmitter emitter = new SseEmitter(300000L);,这个是可以指定超时时间的,如果你不指定的话会变成http连接的过期时间,很有可能你的数据还没有发完,然后这个http连接就断了(可以拿下面的代码试一下,将里面的参数去掉);
在发送数据的时候需要使用另一个线程去执行这个数据的传输,SseEmitter.send(Object object);
SseEmitter.event() .reconnectTime(1000) .id(String.valueOf(i)) .data(WORDS[i])
- reconnectTime:指定浏览器重新发起连接的时间间隔。两种情况会导致浏览器重新发起连接:一种是时间间隔到期,二是由于网络错误等原因,导致连接出错。
- id:数据片段id;
- data:发送的数据体;
例子
@Controller
public class SSEController {
private static final Logger logger = LoggerFactory.getLogger(SSEController.class);
private static final String[] WORDS = "The quick brown fox jumps over the lazy dog.".split(" ");
private final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
@GetMapping(path = "/words", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
SseEmitter getWords(@RequestHeader(name = "Last-Event-ID", required = false) String lastId) {
logger.info("Id of last received event: {}", lastId);
SseEmitter emitter = new SseEmitter(300000L); // 指定超时时间300000毫秒
logger.info("Emitter created: {}", emitter);
cachedThreadPool.execute(() -> {
try {
System.out.println(WORDS.length);
for (int i = parseLastId(lastId); i < WORDS.length; i++) {
emitter.send(
SseEmitter.event()
.reconnectTime(1000)
.id(String.valueOf(i))
.data(WORDS[i])
);
TimeUnit.SECONDS.sleep(5);
}
emitter.complete();
logger.info("Emitter completed: {}", emitter);
} catch (Exception e) {
emitter.completeWithError(e);
logger.error("Emitter failed: {}", emitter, e);
}
});
return emitter;
}
private int parseLastId(String lastId) {
try {
return Integer.parseInt(lastId) + 1;
} catch (NumberFormatException e) {
return 0;
}
}
}