基於sse的訊息單向推送機制
訊息推送現在基本上是web應用的標配,在做一個社交類網站時,本人一開始由於對這方面的技術不夠熟練,想採用最新的websocket技術,卻一直失敗,最終採用了最傳統的輪詢方式,十分浪費資源。今天看了spring boot 實戰這本書,裡面介紹了一種我之前從未了解過的技術——伺服器推送事件(Server-sent Events),簡稱SSE,它可以很方便地實現伺服器向客戶端的單向訊息推送,看起來相當簡單,遂動手嘗試了一下,用起來果然十分方便,因此在此作個筆記,以便日後使用。
在這我就不對這項技術的內部實現進行深入探討了,只談談它如何應用。博主在這裡使用的是java語言,其他語言也類似:
首先建立一個java web專案,新建一個簡單的首頁,程式碼如下:
其中最核心的就是EventSource()物件了,物件裡的引數就是伺服器推送的請求路徑了,要注意的是,EventSource目前並不為IE所支援,請在谷歌或火狐等瀏覽器下嘗試。<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>測試頁面</title> <style> </style> </head> <body class="bgBody"> <div id="msgFromPush"></div> <script src="<%=request.getContextPath()%>/resources/js/jquery-1.11.3.min.js"></script> <script type="text/javascript"> //jsp頁面js指令碼 var source = new EventSource('push');//傳送訊息 s = ''; source.addEventListener('message', function(e) { s += e.data + "<br/>"; $("#msgFromPush").html(s); },false);//新增客戶端的監聽 source.addEventListener('open', function(e) { console.log("連線開啟"); }, false); source.addEventListener('error',function(e){ if(e.currentTarget.readyState==EventSource.CLOSED){ console.log("連線關閉"); }else{ console.log(e.currentTarget.readyState); } }); </script> </body> </html>
eventSource最核心的函式有以下幾個:
我們可以像例項程式碼一樣通過註冊監聽器實現推送接送功能,也可以使用以下這種形式:source.onXXXX=function(e){...}實現。接下來看伺服器端的程式碼:
* 實現伺服器推送 * @param response * @return */ @RequestMapping(value="push",produces="text/event-stream") @ResponseBody public String push(HttpServletResponse response){ Random random=new Random(); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } return "data:Testing 1,2,3"+random.nextInt()+"\n\n"; }
伺服器端無需要使用第三方jar包,只要修改一下響應頭資訊就可以實現推送功能了。要注意的是,推送的資料格式是有規定的,都是如下格式:
field: value\n
field可以取四個值:“data”, “event”, “id”, or “retry”,也就是說有四類頭資訊。每次HTTP通訊可以包含這四類頭資訊中的一類或多類。\n代表換行符。
以冒號開頭的行,表示註釋。通常,伺服器每隔一段時間就會向瀏覽器傳送一個註釋,保持連線不中斷。
資料內容用data表示,可以佔用一行或多行。如果資料只有一行,則像下面這樣,以“\n\n”結尾。
data: message\n\n
如果資料有多行,則最後一行用“\n\n”結尾,前面行都用“\n”結尾。
data: begin message\n
data: continue message\n\n
總之,最後一行的data,結尾要用兩個換行符號,表示資料結束。
以傳送JSON格式的資料為例。
data: {\n
data: "foo": "bar",\n
data: "baz", 555\n
data: }\n\n
大家千萬要記得結尾要兩個換行符,否則前端是無法正確處理資料的,博主可是被這個坑了好久。