SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送
EventSource 的優(yōu)點(diǎn)
- 簡(jiǎn)單易用:EventSource 使用簡(jiǎn)單,基于標(biāo)準(zhǔn)的 HTTP 協(xié)議,無(wú)需復(fù)雜的握手過(guò)程。
- 自動(dòng)重連:EventSource 具有內(nèi)置的重連機(jī)制,確保連接中斷后自動(dòng)重新連接。
- 輕量級(jí):EventSource 使用長(zhǎng)輪詢機(jī)制,消耗的資源相對(duì)較少,適合低帶寬環(huán)境。
- 跨域支持:EventSource 允許在跨域環(huán)境下進(jìn)行通信,通過(guò)適當(dāng)?shù)捻憫?yīng)頭授權(quán)來(lái)自不同域的客戶端連接。
1、SpringBoot實(shí)現(xiàn)SseEmitter
1.1簡(jiǎn)易業(yè)務(wù)層
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Author tm
* Date 2023/9/25
* Version 1.0
*/
@RestController
@RequestMapping(path = "/sysTest/see")
public class SseControllerTest {
private static Map<String, SseEmitter> sseCache = new ConcurrentHashMap<>();
/**
* 前端傳遞標(biāo)識(shí),生成唯一的消息通道
*/
@GetMapping(path = "subscribe", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
public SseEmitter push(String id) throws IOException {
// 超時(shí)時(shí)間設(shè)置為3s,用于演示客戶端自動(dòng)重連
SseEmitter sseEmitter = new SseEmitter(30000L);
// 設(shè)置前端的重試時(shí)間為1s
sseEmitter.send(SseEmitter.event().reconnectTime(1000).data("連接成功"));
sseCache.put(id, sseEmitter);
System.out.println("add " + id);
sseEmitter.onTimeout(() -> {
System.out.println(id + "超時(shí)");
sseCache.remove(id);
});
sseEmitter.onCompletion(() -> System.out.println("完成!??!"));
return sseEmitter;
}
/**
* 根據(jù)標(biāo)識(shí)傳遞信息
*/
@GetMapping(path = "push")
public String push(String id, String content) throws IOException {
SseEmitter sseEmitter = sseCache.get(id);
if (sseEmitter != null) {
sseEmitter.send(SseEmitter.event().name("msg").data("后端發(fā)送消息:" + content));
}
return "over";
}
/**
* 根據(jù)標(biāo)識(shí)移除SseEmitter
*/
@GetMapping(path = "over")
public String over(String id) {
SseEmitter sseEmitter = sseCache.get(id);
if (sseEmitter != null) {
sseEmitter.complete();
sseCache.remove(id);
}
return "over";
}
}
2、Vue3對(duì)接EventSource
const initEventSource = ()=>{
if (typeof (EventSource) !== 'undefined') {
const evtSource = new EventSource('https://xxx.xxx.x.x/sysTest/see/subscribe?id=002', { withCredentials: true }) // 后端接口,要配置允許跨域?qū)傩?
// 與事件源的連接剛打開(kāi)時(shí)觸發(fā)
evtSource.onopen = function(e){
console.log(e);
}
// 當(dāng)從事件源接收到數(shù)據(jù)時(shí)觸發(fā)
evtSource.onmessage = function(e){
console.log(e);
}
// 與事件源的連接無(wú)法打開(kāi)時(shí)觸發(fā)
evtSource.onerror = function(e){
console.log(e);
evtSource.close(); // 關(guān)閉連接
}
// 也可以偵聽(tīng)命名事件,即自定義的事件
evtSource.addEventListener('msg', function(e) {
console.log(e.data)
})
} else {
console.log('當(dāng)前瀏覽器不支持使用EventSource接收服務(wù)器推送事件!');
}
}
3、測(cè)試、驗(yàn)證、使用
使用postMan調(diào)用接口測(cè)試
3.1、 postMan調(diào)用后端"push"接口發(fā)送消息

3.2、前端實(shí)時(shí)接收到數(shù)據(jù)

4、踩坑
4.1、nginx對(duì)于EventSource連接要特殊處理
#eventSource
location /es/ {
proxy_pass http://請(qǐng)求地址/;
#必須要設(shè)置當(dāng)前Connection 屬性
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
}
4.2、連接通道接口類型一定要設(shè)置MediaType.TEXT_EVENT_STREAM_VALUE

4.3、 跨越問(wèn)題,項(xiàng)目地址和接口地址需要在同一域名下

4.4 、EventSource監(jiān)聽(tīng)事件的類型需要與后端發(fā)送的類型一致


到此這篇關(guān)于SpringBoot+SseEmitter和Vue3+EventSource實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)推送的文章就介紹到這了,更多相關(guān)SpringBoot 實(shí)時(shí)數(shù)據(jù)推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java線程安全鎖ReentrantReadWriteLock原理分析readLock
這篇文章主要為大家介紹了java線程安全鎖ReentrantReadWriteLock原理分析readLock,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
SpringBoot集成Druid配置(yaml版本配置文件)詳解
這篇文章主要介紹了SpringBoot集成Druid配置(yaml版本配置文件),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Java精確抽取網(wǎng)頁(yè)發(fā)布時(shí)間
這篇文章主要為大家詳細(xì)介紹了Java精確抽取網(wǎng)頁(yè)發(fā)布時(shí)間的相關(guān)資料,盡量做到精確無(wú)誤,感興趣的小伙伴們可以參考一下2016-06-06
使用Java實(shí)現(xiàn)讀取手機(jī)文件名稱
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)讀取手機(jī)文件名稱,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03

