Spring SseEmitter 系統(tǒng)及作用詳細(xì)講解
SpringSseEmitter系統(tǒng)詳細(xì)講解
一、SSE 基本概念(Server-Sent Events)
- SSE 是 HTML5 提出的標(biāo)準(zhǔn)。
- 客戶端通過
EventSource向服務(wù)端發(fā)起 一個(gè)長連接,服務(wù)器通過該連接持續(xù)向客戶端發(fā)送事件。 - 相比 WebSocket(雙向通信),SSE 是單向的:服務(wù)端 → 客戶端。
- 本質(zhì)上是基于 HTTP 協(xié)議的長連接。
示例(前端代碼)
const eventSource = new EventSource("/sse/subscribe");
eventSource.onmessage = function(event) {
console.log("收到消息:", event.data);
};
eventSource.onerror = function(e) {
console.error("連接錯(cuò)誤", e);
};二、Spring 的SseEmitter作用
Spring 提供了 SseEmitter 類來簡(jiǎn)化 SSE 的開發(fā),它本質(zhì)上是一個(gè) Controller 的返回對(duì)象,用于不斷地往前端推送數(shù)據(jù)。
三、基本用法
1. 添加依賴(Spring Boot Web 項(xiàng)目一般已包含)
<!-- Maven 中無需額外添加,spring-boot-starter-web 已包含 -->
2. 控制器定義 SSE 接口
@RestController
public class SseController {
@GetMapping("/sse/subscribe")
public SseEmitter subscribe() {
SseEmitter emitter = new SseEmitter(0L); // 不超時(shí),或設(shè)置時(shí)間,如30_000L
Executors.newSingleThreadExecutor().submit(() -> {
try {
for (int i = 1; i <= 5; i++) {
emitter.send("第 " + i + " 條消息");
Thread.sleep(1000);
}
emitter.complete(); // 關(guān)閉連接
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}四、SseEmitter 的重要方法
| 方法 | 說明 |
|---|---|
send(Object data) | 向客戶端發(fā)送消息,支持字符串、JSON 等 |
send(Object data, MediaType mediaType) | 指定 MIME 類型發(fā)送 |
complete() | 正常關(guān)閉連接 |
completeWithError(Throwable ex) | 異常關(guān)閉連接 |
onCompletion(Runnable callback) | 設(shè)置連接關(guān)閉的回調(diào) |
onTimeout(Runnable callback) | 設(shè)置超時(shí)回調(diào) |
onError(Consumer<Throwable> callback) | 設(shè)置錯(cuò)誤回調(diào) |
setTimeout(long timeout) | 設(shè)置連接超時(shí)時(shí)間(默認(rèn) 30 秒) |
五、注意事項(xiàng)
1. Content-Type
Content-Type: text/event-stream
Spring 會(huì)自動(dòng)設(shè)置,只需:
@GetMapping(value = "/sse/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
2. 瀏覽器自動(dòng)重連機(jī)制
- 如果服務(wù)端關(guān)閉連接(未調(diào)用
.complete()),瀏覽器會(huì)默認(rèn)自動(dòng)嘗試重新連接。 - 禁止客戶端重連可發(fā)送
retry: 0。
3. 多用戶支持
private final Map<String, SseEmitter> userEmitters = new ConcurrentHashMap<>();
@GetMapping("/subscribe/{userId}")
public SseEmitter subscribe(@PathVariable String userId) {
SseEmitter emitter = new SseEmitter(60_000L);
userEmitters.put(userId, emitter);
emitter.onCompletion(() -> userEmitters.remove(userId));
emitter.onTimeout(() -> userEmitters.remove(userId));
return emitter;
}
public void sendToUser(String userId, String message) throws IOException {
SseEmitter emitter = userEmitters.get(userId);
if (emitter != null) {
emitter.send(message);
}
}六、典型應(yīng)用場(chǎng)景
- 實(shí)時(shí)進(jìn)度條
- 實(shí)時(shí)通知系統(tǒng)
- 日志推送
- 后臺(tái)任務(wù)結(jié)果反饋
七、SseEmitter 與 WebSocket 的對(duì)比
| 比較項(xiàng) | SSE(SseEmitter) | WebSocket |
|---|---|---|
| 通信方向 | 單向(服務(wù)端 → 客戶端) | 雙向 |
| 協(xié)議 | HTTP | ws:// 或 wss:// |
| 瀏覽器支持 | 廣泛支持 | 廣泛支持 |
| 實(shí)現(xiàn)復(fù)雜度 | 簡(jiǎn)單 | 需要管理連接 |
| 使用場(chǎng)景 | 實(shí)時(shí)推送 | 聊天、游戲等 |
八、SseEmitter 高級(jí)技巧
? 自定義事件名稱
emitter.send(SseEmitter.event()
.name("customEvent")
.data("這是自定義事件")
);前端監(jiān)聽:
eventSource.addEventListener("customEvent", function(event) {
console.log("收到自定義事件:", event.data);
});? 定時(shí)心跳保持連接
ScheduledExecutorService heartbeatScheduler = Executors.newScheduledThreadPool(1);
heartbeatScheduler.scheduleAtFixedRate(() -> {
try {
emitter.send("heartbeat");
} catch (IOException e) {
emitter.completeWithError(e);
}
}, 0, 15, TimeUnit.SECONDS);九、總結(jié)
| 特性 | 支持情況 |
|---|---|
| 異步發(fā)送 | ? |
| 多用戶并發(fā) | ? |
| 超時(shí)與關(guān)閉管理 | ? |
| 自定義事件類型 | ? |
| 應(yīng)用場(chǎng)景 | 實(shí)時(shí)推送、輕量通知 |
到此這篇關(guān)于Spring SseEmitter 系統(tǒng)詳細(xì)講解的文章就介紹到這了,更多相關(guān)Spring SseEmitter 系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot處理跨域請(qǐng)求(CORS)的五種方式
跨域資源共享(CORS)是現(xiàn)代Web開發(fā)中常見的問題,Spring?Boot提供了多種方式來處理CORS請(qǐng)求,下面我將詳細(xì)介紹各種實(shí)現(xiàn)方式及其適用場(chǎng)景,需要的朋友可以參考下2025-04-04
Eclipse運(yùn)行android項(xiàng)目報(bào)錯(cuò)Unable to build: the file dx.jar was not
今天小編就為大家分享一篇關(guān)于Eclipse運(yùn)行android項(xiàng)目報(bào)錯(cuò)Unable to build: the file dx.jar was not loaded from the SDK folder的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12
Java Socket編程心跳包創(chuàng)建實(shí)例解析
這篇文章主要介紹了Java Socket編程心跳包創(chuàng)建實(shí)例解析,具有一定借鑒價(jià)值,需要的朋友可以參考下2017-12-12
JAVA操作MongoDB數(shù)據(jù)庫實(shí)例教程
MongoDB是一個(gè)文檔型數(shù)據(jù)庫,是NOSQL家族中最重要的成員之一,下面這篇文章主要給大家介紹了關(guān)于JAVA操作MongoDB數(shù)據(jù)庫的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
Servlet實(shí)現(xiàn)簡(jiǎn)單文件上傳功能
這篇文章主要為大家詳細(xì)介紹了Servlet實(shí)現(xiàn)簡(jiǎn)單文件上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Java使用flyway實(shí)現(xiàn)腳本自動(dòng)化的方法詳解
Flyway是一個(gè)開源的數(shù)據(jù)庫版本控制工具,主要用于管理數(shù)據(jù)庫的版本和變更,它可以自動(dòng)化地將數(shù)據(jù)庫遷移到不同的版本,同時(shí)支持多種數(shù)據(jù)庫類型,本文給大家介紹了如何使用flyway實(shí)現(xiàn)腳本自動(dòng)化,需要的朋友可以參考下2023-10-10
使用Spring?Boot快速構(gòu)建一個(gè)簡(jiǎn)單的文件處理工具
在現(xiàn)代Web應(yīng)用中,文件上傳與處理是常見的需求,本文將通過一個(gè)實(shí)際案例,詳細(xì)介紹如何使用Spring?Boot構(gòu)建一個(gè)文件處理工具,感興趣的小伙伴可以參考一下2025-06-06

