Spring 框架中的 SseEmitter 使用原理解析
在需要實(shí)時(shí)向前端推送數(shù)據(jù)時(shí),很多人第一反應(yīng)是 WebSocket。但如果你的需求是“服務(wù)端單向推送”,并不需要客戶(hù)端向后端發(fā)送消息,那么 Spring 提供的 SseEmitter 會(huì)更加輕量、更易用,而且天然支持?jǐn)嗑€重連。本文總結(jié)了 SseEmitter 的核心原理、常見(jiàn)用法、注意事項(xiàng)以及生產(chǎn)實(shí)踐經(jīng)驗(yàn)。
一、SseEmitter 是什么?
SseEmitter 是 Spring MVC 提供的一個(gè)類(lèi),用于實(shí)現(xiàn) 基于 HTTP 的服務(wù)器單向推送(Server-Sent Events)。
它的特點(diǎn)包括:
- 單向推送(服務(wù)端 → 客戶(hù)端)
- 基于標(biāo)準(zhǔn) HTTP(不需要新協(xié)議)
- 支持自動(dòng)重連(瀏覽器 EventSource 自帶)
- 使用簡(jiǎn)單比 WebSocket 更輕,更適合消息通知類(lèi)業(yè)務(wù)
適用場(chǎng)景:
- 消息提醒
- 實(shí)時(shí)狀態(tài)更新
- 任務(wù)進(jìn)度推送
- 監(jiān)控?cái)?shù)據(jù)刷新
二、基礎(chǔ)用法示例
1. 創(chuàng)建 SSE 連接接口
@GetMapping("/sse/connect")
public SseEmitter connect() {
SseEmitter emitter = new SseEmitter(0L); // 0 表示不過(guò)期
// 在連接時(shí)發(fā)送一條消息
try {
emitter.send("連接成功");
} catch (Exception e) {
emitter.completeWithError(e);
}
return emitter;
}
注意:
new SseEmitter(0L)表示不超時(shí),可減少長(zhǎng)連接斷開(kāi)問(wèn)題。- 返回后客戶(hù)端會(huì)進(jìn)入持續(xù)接收狀態(tài)。
三、服務(wù)端主動(dòng)推送消息
@Autowired
private List<SseEmitter> emitters = new CopyOnWriteArrayList<>();
@GetMapping("/sse/connect")
public SseEmitter connect() {
SseEmitter emitter = new SseEmitter(0L);
emitters.add(emitter);
emitter.onCompletion(() -> emitters.remove(emitter));
emitter.onTimeout(() -> emitters.remove(emitter));
return emitter;
}
@PostMapping("/sse/send")
public void sendMessage(@RequestParam String msg) {
for (SseEmitter emitter : emitters) {
try {
emitter.send(msg);
} catch (Exception e) {
emitter.complete();
}
}
}關(guān)鍵點(diǎn):
- 使用
CopyOnWriteArrayList保存所有連接 - 斷開(kāi)/異常時(shí)及時(shí)清理 emitter
- 推送時(shí)遍歷所有 emitter
四、前端(瀏覽器)接收實(shí)現(xiàn)
const evtSource = new EventSource("/sse/connect");
evtSource.onmessage = function (event) {
console.log("收到消息:", event.data);
};瀏覽器自帶特性:斷線自動(dòng)重連,不需要你自己實(shí)現(xiàn)。
五、常見(jiàn)問(wèn)題與解決方案
1.前端收不到消息?(最常見(jiàn))
原因可能是:
- 沒(méi)有使用 UTF-8 文本格式
- 推送內(nèi)容太大或太快
- 連接被代理/網(wǎng)關(guān)斷開(kāi)
解決:
emitter.send(SseEmitter.event().data("內(nèi)容").id("1").name("msg"));2.Nginx 或網(wǎng)關(guān) 1 分鐘斷開(kāi)
這是行業(yè)常見(jiàn)問(wèn)題,需要配置:
proxy_read_timeout 3600; proxy_send_timeout 3600;
3.Spring 默認(rèn)超時(shí)導(dǎo)致斷開(kāi)
務(wù)必使用:
new SseEmitter(0L);
4.消息推送異常導(dǎo)致連接中斷
一定要在異常時(shí)清理 emitter:
catch (Exception e) {
emitter.completeWithError(e);
}
六、生產(chǎn)實(shí)踐建議
- 使用 心跳包 防止代理斷開(kāi)(比如每 20 秒發(fā)送一次空事件)
- 使用 CopyOnWriteArrayList 或 ConcurrentHashMap 存儲(chǔ)用戶(hù)連接
- 對(duì)每個(gè)發(fā)送操作包一層 try/catch,避免單個(gè)連接阻塞所有推送
- 數(shù)據(jù)頻繁更新建議加上消息合并策略,避免推太快導(dǎo)致阻塞
總結(jié)
SseEmitter 是一個(gè)輕量但功能強(qiáng)大的實(shí)時(shí)推送工具,特別適合實(shí)時(shí)通知類(lèi)業(yè)務(wù)。相比 WebSocket,它更簡(jiǎn)單,不需要復(fù)雜協(xié)議和框架即可實(shí)現(xiàn)穩(wěn)定的實(shí)時(shí)消息推送。
如果你的業(yè)務(wù)屬于“服務(wù)端單向推送”,SseEmitter 往往是最優(yōu)選擇。
到此這篇關(guān)于Spring 框架中的 SseEmitter 使用原理解析的文章就介紹到這了,更多相關(guān)Spring SseEmitter 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring SseEmitter 系統(tǒng)及作用詳細(xì)講解
- 如何使用 SseEmitter 實(shí)現(xiàn) Spring Boot 后端的流式傳輸和前端的數(shù)據(jù)接收
- Springboot SseEmitter流式輸出的實(shí)現(xiàn)代碼
- SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送
- Spring之SseEmitter實(shí)現(xiàn)讓你的進(jìn)度條實(shí)時(shí)更新
- Spring SseEmitter推送消息及常用方法
相關(guān)文章
編碼實(shí)現(xiàn)從無(wú)序鏈表中移除重復(fù)項(xiàng)(C和JAVA實(shí)例)
如果不能使用臨時(shí)緩存,你怎么實(shí)現(xiàn)無(wú)序鏈表中移除重復(fù)項(xiàng)(?C和JAVA實(shí)例無(wú)序鏈表中移除重復(fù)項(xiàng)。2013-10-10
JSON Web Token(JWT)原理入門(mén)教程詳解
這篇文章主要為大家介紹了JSON Web Token(JWT)原理入門(mén)教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
解決spring?data?jpa?saveAll()?保存過(guò)慢問(wèn)題
這篇文章主要介紹了解決spring?data?jpa?saveAll()保存過(guò)慢問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
mybatis中查詢(xún)結(jié)果為空時(shí)不同返回類(lèi)型對(duì)應(yīng)返回值問(wèn)題
這篇文章主要介紹了mybatis中查詢(xún)結(jié)果為空時(shí)不同返回類(lèi)型對(duì)應(yīng)返回值問(wèn)題,本文分幾種方法給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-10-10
微信APP支付(IOS手機(jī)端+java后臺(tái))版
這篇文章主要為大家詳細(xì)介紹了微信APP支付(IOS手機(jī)端+java后臺(tái))版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
Java通過(guò)jedis連接redis的幾種常用方法
jedis封裝了redis原有的操作命令,使用起來(lái)很簡(jiǎn)單,本文主要介紹了Java通過(guò)jedis連接redis的幾種常用方法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03
Java socket通信模擬QQ實(shí)現(xiàn)多人聊天室
Socket在Java實(shí)戰(zhàn)網(wǎng)絡(luò)通信編程應(yīng)用中有非常重要的作用,你想要跟別人聯(lián)系都得通過(guò)socket占據(jù)端口來(lái)實(shí)現(xiàn),掌握Socket技術(shù)不僅在聊天應(yīng)用程序中需要用到(比如QQ什么的都都是用socket來(lái)寫(xiě)的),而且對(duì)于學(xué)習(xí) Asp.net 也非常有幫助2022-07-07

