一、SSE 的本質
HTTP 協議無法做到服務器主動推送信息。但是,有一種變通方法,就是服務器向客戶端聲明,接下來要發送的是流信息(streaming)。
也就是說,發送的不是一次性的數據包,而是一個數據流,會連續不斷地發送過來。這時,客戶端不會關閉連接,會一直等着服務器發過來的新的數據流,視頻播放就是這樣的例子。本質上,這種通信就是以流信息的方式,完成一次用時很長的下載。
SSE 就是利用這種機制,使用流信息向瀏覽器推送信息。它基於 HTTP 協議,目前除了 IE/Edge,其他瀏覽器都支持。
三、集成
SpringMVC內置SseEmitter類內置了一些方法,方便我們使用SSE(Server Sent Event)向瀏覽器推送數據。
1.sse機制不同於傳統的“請求-響應”模型,在前端必須使用EventSource對象請求我們的接口,創建一個連接,
var source = new EventSource('url');
withCredentials:表示是否一起發送 Cookie。
var source = new EventSource(url, { withCredentials: true });
2.然後監聽服務端發送過來的事件。
下圖中監聽的爲服務端通過我們上面創建的連接發送過來的message(默認)事件,服務端也可以自定義發送的事件。
source.addEventListener('message', function (e) {
//do something
});
除了我們上面所說的事件,還有open和error事件
source.addEventListener('open', function (e) {
//do something
}, false);
source.addEventListener('error', function (e) {
if (e.readyState == EventSource.CLOSED) {
//do something
} else {
//do something
}
}, false);
- 相當於常量
EventSource.CONNECTING
,表示連接還未建立,或者斷線正在重連。 - 相當於常量
EventSource.OPEN
,表示連接已經建立,可以接受數據。 - 相當於常量
EventSource.CLOSED
,表示連接已斷,且不會重連。
3.服務端需要創建一個SseEmitter對象,然後使用改對象發送數據
@ResponseBody
@RequestMapping(value = "url", method = RequestMethod.GET, produces = {"text/event-stream;charset=UTF-8"})
public SseEmitter getUnitAreaInfoSSE(HttpServletRequest request, HttpServletResponse response){
SseEmitter event = new SseEmitter();
try {
// 添加一些額外配置
event.send(SseEmitter.event().reconnectTime(10000L).id("123"));
Thread thread2 = new Thread(new ThreadDemo2(event, userDao));
thread2.start();
return event;
} catch (IOException e) {
System.out.println(e.toString());
}
return event;
}
創建對象的時候可以自定義重新創建連接的時間。
然後啓動一個新的線程去發送數據(目前只想到了這種方法,如果有其他方法歡迎留言)。
class ThreadDemo2 implements Runnable {
private SseEmitter event;
public ThreadDemo2(SseEmitter event, UserDao userDao) {
this.event = event;
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(2000);
System.out.println("數據推送--------" + "服務器端數據");
event.send(SseEmitter.event().data("服務器端數據"));
} catch (IOException | InterruptedException e) {
System.out.println(e.toString());
}
}
}
}