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