使用Java和SpringBoot實現(xiàn)服務(wù)器發(fā)送事件(Server-Sent Events)
引言
使用Java
開發(fā)web
應(yīng)用,大多數(shù)時候我們提供的接口返回數(shù)據(jù)都是一次性完整返回。有些時候,我們也需要提供流式接口持續(xù)寫出數(shù)據(jù),以下提供一種簡單的方式。
SSE(Server-Sent Events)
SSE
是一種允許服務(wù)器單向發(fā)送事件到客戶端的技術(shù),它基于HTTP
協(xié)議,服務(wù)器可以推送消息到客戶端,但客戶端不能向服務(wù)器發(fā)送消息。
實現(xiàn)
直接上代碼
@RestController public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @GetMapping("/test") public void test(HttpServletResponse response) { response.setContentType("text/event-stream"); response.setCharacterEncoding("utf-8"); try (final PrintWriter writer = response.getWriter()) { // 要推送的內(nèi)容 final String content = "你好,我的朋友,快過年了,提前祝你新年快樂!"; int len = content.length(); int endIndex = 0; // 每隔2個字符推送一次,模擬打字機效果 while (endIndex < len) { endIndex = Math.min(endIndex + 2, len); final String subContent = content.substring(0, endIndex); // 將要推送的內(nèi)容封裝成JSON格式,模擬實際開發(fā)中的數(shù)據(jù)格式,非必須 final JSONObject json = new JSONObject(); json.put("data", subContent); json.put("code", HttpStatus.OK.value()); // 最后一次推送時,type為finish,表示推送結(jié)束,其它情況為add final String type = endIndex == len ? "finish" : "add"; json.put("type", type); // 組裝成SSE格式的數(shù)據(jù),發(fā)送給前端,這個格式(data: content\n\n)是固定的,content是自定義的推送內(nèi)容 writer.write("data: " + json.toJSONString() + "\n\n"); writer.flush(); // 稍微給點停頓,防止數(shù)據(jù)發(fā)送太快,瀏覽器接收不過來 TimeUnit.MILLISECONDS.sleep(100); } } catch (Exception e) { Thread.currentThread().interrupt(); logger.error("流式推送數(shù)據(jù)異常", e); } } }
組裝數(shù)據(jù),格式固定為"data: " + content + "\n\n"
,這里的數(shù)據(jù)格式是服務(wù)器發(fā)送事件(Server-Sent Events,SSE
)的標(biāo)準(zhǔn)格式。
在 SSE
中,數(shù)據(jù)必須以 "data: "
開頭,然后是要發(fā)送的數(shù)據(jù),最后是兩個換行符"\n\n"
。這是SSE
的規(guī)定格式,客戶端會根據(jù)這種格式來解析服務(wù)器發(fā)送的事件。
接口調(diào)試
用接口調(diào)試工具(我用的是Apifox
)調(diào)試接口如下:
接口符合SSE
規(guī)范,所以可以被正常識別為事件流推送。
SSE與其他實時通信技術(shù)的比較
SSE與WebSocket的比較
- 通信方式:SSE是單向的,只能由服務(wù)器向客戶端發(fā)送數(shù)據(jù);而WebSocket是雙向的,服務(wù)器和客戶端都可以發(fā)送數(shù)據(jù)。
- 協(xié)議:SSE基于HTTP協(xié)議,更易于設(shè)置和配置;WebSocket是一個獨立的協(xié)議。
- 數(shù)據(jù)格式:SSE發(fā)送的數(shù)據(jù)格式固定,必須是"text/event-stream";而WebSocket可以發(fā)送任何類型的數(shù)據(jù)。
- 連接:SSE在斷開連接后可以自動重新連接,而WebSocket需要手動處理重連。
- 瀏覽器支持:WebSocket的瀏覽器支持更廣泛,幾乎所有現(xiàn)代瀏覽器都支持WebSocket;而SSE在某些舊版本的瀏覽器(如IE)中不被支持。
SSE與長輪詢的比較
- 效率:SSE更高效,因為它只需要一個HTTP連接,就可以持續(xù)地發(fā)送數(shù)據(jù);而長輪詢需要不斷地建立和斷開HTTP連接。
- 實時性:SSE的實時性更強,因為服務(wù)器可以隨時發(fā)送數(shù)據(jù);而長輪詢需要客戶端不斷地發(fā)送請求來獲取新數(shù)據(jù)。
- 復(fù)雜性:SSE的實現(xiàn)相對簡單,只需要服務(wù)器按照規(guī)定的格式發(fā)送數(shù)據(jù)即可;而長輪詢的實現(xiàn)較復(fù)雜,需要處理連接的建立和斷開,以及錯誤和超時等問題。
- 瀏覽器支持:與WebSocket相比,SSE和長輪詢的瀏覽器支持都較差,但長輪詢在更多的瀏覽器中被支持。
- 適用場景:SSE適用于服務(wù)器需要主動推送數(shù)據(jù)的場景;而長輪詢適用于客戶端需要定期獲取新數(shù)據(jù),但服務(wù)器不需要主動推送數(shù)據(jù)的場景。
注意事項
- 以上一個簡單的事件流推送接口就實現(xiàn)好了,但是它的問題是客戶端沒法干預(yù)服務(wù)器的推流,如果需要中途停止接收內(nèi)容,基于以上接口是沒法做到的。所以實際項目開發(fā)過程中,可以使用
Spring
框架提供的SseEmitter
- ?????瀏覽器支持:并非所有瀏覽器都支持
SSE
,例如,舊版本的Internet Explorer就不支持SSE
。在使用SSE
時,需要確保目標(biāo)用戶的瀏覽器支持這項技術(shù)。 - 連接限制:由于
SSE
需要保持長連接,因此可能會占用大量的服務(wù)器資源。在使用SSE
時,需要考慮到這一點,并根據(jù)實際情況進行優(yōu)化。
以上就是使用Java和SpringBoot實現(xiàn)服務(wù)器發(fā)送事件(Server-Sent Events)的詳細內(nèi)容,更多關(guān)于Java SpringBoot服務(wù)器發(fā)送事件的資料請關(guān)注腳本之家其它相關(guān)文章!
- springboot整合websocket后啟動報錯(javax.websocket.server.ServerContainer not available)
- SpringBoot服務(wù)設(shè)置禁止server.point端口的使用
- springboot中server.ssl.key-store配置路徑的問題小結(jié)
- SpringBoot中的server.context-path的實現(xiàn)
- SpringBoot實現(xiàn)Server-Sent Events(SSE)的使用完整指南
- SpringBoot開啟server:compression:enabled(Illegal character ((CTRL-CHAR, code 31)))的問題解決
相關(guān)文章
java中實體類實現(xiàn)時間日期自動轉(zhuǎn)換方式
這篇文章主要介紹了java中實體類實現(xiàn)時間日期自動轉(zhuǎn)換方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06Java 中使用數(shù)組存儲和操作數(shù)據(jù)
本文將介紹Java中常用的數(shù)組操作方法,通過詳細的示例和解釋,幫助讀者全面理解和掌握這些方法,具有一定的參考價值,感興趣的可以了解一下2023-09-09Struts2中ognl遍歷數(shù)組,list和map方法詳解
這篇文章主要介紹了Struts2中ognl遍歷數(shù)組,list和map方法詳解,需要的朋友可以參考下。2017-09-09關(guān)于ElasticSearch的常用增刪改查DSL和代碼
這篇文章主要介紹了關(guān)于ElasticSearch的常用增刪改查DSL和代碼,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04如何在Spring Boot應(yīng)用程序中配置了兩個不同的SOAP Web服務(wù)端點
這篇文章主要介紹了如何在Spring Boot應(yīng)用程序中配置了兩個不同的SOAP Web服務(wù)端點,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進行排序
這篇文章主要介紹了如何對Mysql數(shù)據(jù)表查詢出來的結(jié)果進行排序問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08Servlet連接數(shù)據(jù)庫實現(xiàn)用戶登錄的實現(xiàn)示例
本文主要介紹了Servlet連接數(shù)據(jù)庫實現(xiàn)用戶登錄的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06