使用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個字符推送一次,模擬打字機(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ā)送給前端,這個格式(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ù),最后是兩個換行符"\n\n"。這是SSE的規(guī)定格式,客戶端會根據(jù)這種格式來解析服務(wù)器發(fā)送的事件。
接口調(diào)試
用接口調(diào)試工具(我用的是Apifox)調(diào)試接口如下:

接口符合SSE規(guī)范,所以可以被正常識別為事件流推送。
SSE與其他實(shí)時(shí)通信技術(shù)的比較
SSE與WebSocket的比較
- 通信方式:SSE是單向的,只能由服務(wù)器向客戶端發(fā)送數(shù)據(jù);而WebSocket是雙向的,服務(wù)器和客戶端都可以發(fā)送數(shù)據(jù)。
- 協(xié)議:SSE基于HTTP協(xié)議,更易于設(shè)置和配置;WebSocket是一個獨(dú)立的協(xié)議。
- 數(shù)據(jù)格式:SSE發(fā)送的數(shù)據(jù)格式固定,必須是"text/event-stream";而WebSocket可以發(fā)送任何類型的數(shù)據(jù)。
- 連接:SSE在斷開連接后可以自動重新連接,而WebSocket需要手動處理重連。
- 瀏覽器支持:WebSocket的瀏覽器支持更廣泛,幾乎所有現(xiàn)代瀏覽器都支持WebSocket;而SSE在某些舊版本的瀏覽器(如IE)中不被支持。
SSE與長輪詢的比較
- 效率:SSE更高效,因?yàn)樗恍枰粋€HTTP連接,就可以持續(xù)地發(fā)送數(shù)據(jù);而長輪詢需要不斷地建立和斷開HTTP連接。
- 實(shí)時(shí)性:SSE的實(shí)時(shí)性更強(qiáng),因?yàn)榉?wù)器可以隨時(shí)發(fā)送數(shù)據(jù);而長輪詢需要客戶端不斷地發(fā)送請求來獲取新數(shù)據(jù)。
- 復(fù)雜性:SSE的實(shí)現(xiàn)相對簡單,只需要服務(wù)器按照規(guī)定的格式發(fā)送數(shù)據(jù)即可;而長輪詢的實(shí)現(xiàn)較復(fù)雜,需要處理連接的建立和斷開,以及錯誤和超時(shí)等問題。
- 瀏覽器支持:與WebSocket相比,SSE和長輪詢的瀏覽器支持都較差,但長輪詢在更多的瀏覽器中被支持。
- 適用場景:SSE適用于服務(wù)器需要主動推送數(shù)據(jù)的場景;而長輪詢適用于客戶端需要定期獲取新數(shù)據(jù),但服務(wù)器不需要主動推送數(shù)據(jù)的場景。
注意事項(xiàng)
- 以上一個簡單的事件流推送接口就實(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需要保持長連接,因此可能會占用大量的服務(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ā)送事件的資料請關(guān)注腳本之家其它相關(guān)文章!
- springboot整合websocket后啟動報(bào)錯(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 Map轉(zhuǎn)Object與Object轉(zhuǎn)Map實(shí)現(xiàn)代碼
這篇文章主要介紹了 java Map轉(zhuǎn)Object與Object轉(zhuǎn)Map實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02
SpringBoot實(shí)現(xiàn)application.yml文件敏感信息加密
本文主要介紹了SpringBoot實(shí)現(xiàn)application.yml文件敏感信息加密,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Spring Task定時(shí)任務(wù)的配置和使用詳解
本篇文章主要介紹了Spring Task定時(shí)任務(wù)的配置和使用詳解,實(shí)例分析了Spring Task定時(shí)任務(wù)的配置和使用的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
Java聊天室之實(shí)現(xiàn)客戶端一對一聊天功能
這篇文章主要為大家詳細(xì)介紹了Java簡易聊天室之實(shí)現(xiàn)客戶端一對一聊天功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以了解一下2022-10-10
Spring?IoC容器與Bean管理項(xiàng)目實(shí)踐指南
IoC容器的主要作用是解決組件之間的耦合問題,通過將組件之間的依賴關(guān)系交給IoC容器來管理,可以在不改變組件的代碼的情況下實(shí)現(xiàn)組件之間的解耦,這篇文章主要介紹了Spring?IoC容器與Bean管理項(xiàng)目的相關(guān)資料,需要的朋友可以參考下2025-08-08
spring boot 常見http請求url參數(shù)獲取方法
這篇文章主要介紹了spring boot 常見http請求url參數(shù)獲取,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03

