項目需求:數據展示實時更新
解決方案:在第一時間想到的是通過前端輪詢的方式請求后端接口,達到數據更新的目的,但是存在以下缺點
數據不能做到實施更新,有一定時間的延遲
消耗大量的系統資源
優化方案:使用EventSource的方式來實現該需求,能夠解決以上問題
目錄
1. EventSource基本介紹
2. EventSource特性
3. EventSource工作原理
4. EventSource常用方法
5. 實戰案例:Vue+SpringBoot
1. EventSource基本介紹
EventSource是一種用于實現服務器推送事件的Web API,它允許服務器向客戶端發送數據流,而無需客戶端發出請求。EventSource架構的設計思想是建立一種持久連接,通過這個連接發送事件流,以實現通信。
2. EventSource特性
實時性。EventSource能夠實現實時地數據傳輸,可以在服務器端有新事件時立即向客戶端推送,并自動進行展示。
低延遲。由于EventSource采用長連接的方式進行傳輸,相比于普通的輪詢方式,它能夠更加高效地傳輸數據。
易用性。EventSource是一種非常易用的API,只需要在客戶端創建一個EventSource對象,指定服務器端的URL,即可進行監聽并展示事件。
兼容性。EventSource能夠同時兼容WebSocket和長輪詢等方式,具備很好的兼容性,可以在各種不同的場景下使用。
3. EventSource工作原理
EventSource的原理基于Http協議,它允許服務器與客戶端建立持久的連接,以便服務器能夠向客戶端推送事件數據。以下是EventSource的工作原理客戶端發起請求:客戶端通過創建一個EventSource對象,并向服務器發起一個HTTP GET請求,請求一個特定的URL。
服務器響應:服務器接收客戶端的請求,并在HTTP頭中添加Content-Type: text/event-stream
,表明將發送的事件數據格式為text/event-stream。
建立持久連接:服務器與客戶端建立一個持續的HTTP連接,并開始向客戶端發送數據,直到連接被關閉。
發送事件數據:當服務器有新的事件數據要發送時,它將按照特定格式發送給客戶端。事件數據通常以event:eventName;data:eventData;
的形式發送,其中event
字段表示事件名,data
字段表示事件數據。
客戶端接收數據:客戶端通過EventSource對象注冊事件處理函數,以接收來自服務器的事件數據。當接收到事件數據時,客戶端會創建一個Event對象,并觸發相應的事件處理函數,傳遞Event對象作為參數。Event對象包含type
(事件類型,通常為"message")、data
(事件數據)、lastEventId
(上一個事件的ID)、origin
(事件源的URL)等屬性。
錯誤處理和重連:如果連接出現錯誤或被關閉,客戶端將觸發“error”事件或“close”事件,以便進行錯誤處理或重新連接。
單向通信:EventSource支持單向通信,即只能從服務器向客戶端推送數據,不支持客戶端向服務器發送數據。這種特性使它適用于需要實時更新的應用程序場景,如聊天室、股票市場等。
自動重連接:EventSource支持自動重連接功能,如果連接中斷,它可以嘗試自動恢復連接。
發送隨機事件:EventSource允許服務器發送沒有明確事件名的隨機事件,這種情況下,如果沒有指定事件名的匹配事件處理函數,則會觸發通用事件處理函數。
總的來說,EventSource提供了一種簡單的方式來實現服務器向客戶端的實時數據推送,特別適合于不需要雙向通信的場景。
4. EventSource常用方法
1. 創建EventSource對象,其中url是服務器端推送數據的地址。
var evtSource = new EventSource(url);
2. onopen:連接建立時觸發
evtSource.onopen = function () {
console.log("Connection to server opened.");
3. onmessage:接收到服務器端發送的數據時觸發。
evtSource.onmessage = (e) => {
4. onerror:連接出錯時觸發。
evtSource.onerror = function () {
5. 實戰案例:Vue+SpringBoot
前端代碼:
methods: {
handleEventSoure() {
const eventSource = new EventSource('/source/test') // 連接地址
eventSource.onopen = () => { // 開始連接
console.log("連接成功")
}
eventSource.onmessage = (event) => { // 接收消息
console.log(event.data)
}
eventSource.onerror = () => { // 連接失敗
console.log("連接失敗")
}
},
},
mounted() {
this.handleEventSoure()
}
后端代碼:
@RestController
@RequestMapping("/source")
public class SysLoginInfoController extends BaseController {
@GetMapping("/test")
public Flux<String> test(HttpServletResponse response, HttpServletRequest req) {
//設置響應的內容類型為HTML,字符集為UTF-8。
response.setContentType("text/html;charset=utf-8");
// 設置響應頭,指明這是一個EventSource響應
response.setHeader("Content-Type", "text/event-stream");
//設置響應頭"Cache-Control"為"no-cache",表示不允許緩存此響應。
response.setHeader("Cache-Control", "no-cache");
//設置響應頭"Connection"為"keep-alive",表示保持連接。
response.setHeader("Connection", "keep-alive");
//返回的是一個字符串流 返回數據:好的 + 當前時間
return Flux.interval(Duration.ofSeconds(1)).map(sequence -> "data: 好的" + new Date() + "");
}
}
效果展示:
至此大功告成。
該文章在 2024/6/15 11:13:24 編輯過