SSE简介
严格地说,HTTP 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息(streaming)。
也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。本质上,这种通信就是以流信息的方式,完成一次用时很长的下载。
SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 HTTP 协议,目前除了 IE/Edge,其他浏览器都支持。
--------Server-Sent Events 教程 - 阮一峰的网络日志
服务端实现
SpringMVC支持了SSE,所以不需要引入额外的包。SpringMVC实现SSE主要借助ResponseBodyEmitter
或SseEmitter
,SseEmitter
是ResponseBodyEmitter
的子类。访问Asynchronous Requests :: Spring Framework查看官方对SSE实现的介绍。
java
@RestController
public class SseSampleController {
ExecutorService executorService = Executors.newSingleThreadExecutor();
@GetMapping("/sse")
@CrossOrigin()
public SseEmitter sse() {
SseEmitter emitter = new SseEmitter();
emitter.onTimeout(() -> System.out.println("timeout"));
emitter.onCompletion(() -> System.out.println("completion"));
emitter.onError((e) -> System.out.println("error"));
executorService.submit(() -> {
try {
emitter.send(SseEmitter.event().id("1").data("start"));
for (int i = 0; i < 5; i++) {
emitter.send(SseEmitter.event().id("1").data(i));
Thread.sleep(1000);
}
emitter.send(SseEmitter.event().id("1").data("end"));
emitter.complete();
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}
客户端实现
客户端主要使用js的EventSource
对象。
javascript
eventSource = new EventSource("http://localhost:8090/sse")
eventSource.onerror=()=>eventSource.close()
eventSource.onmessage=(event)=>console.log(event.data)
部署测试
SseSampleController
类已经通过@CrossOrigin
注解允许跨域访问,可以在浏览器控制台上直接执行客户端代码。