SpringMVC使用SSE向瀏覽器推送數據

一、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());
			}
       	}
    }
     
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章