使用SSE流式輸出實(shí)戰(zhàn)記錄(Javaweb前后端)
一.什么是SSE?
SSE(Server-Sent Events)是一種在Web應(yīng)用中實(shí)現(xiàn)單向?qū)崟r(shí)通信的技術(shù)。通過(guò)SSE,服務(wù)器可以主動(dòng)向客戶端發(fā)送更新,而無(wú)需客戶端不斷發(fā)起請(qǐng)求。這對(duì)于需要實(shí)時(shí)更新的應(yīng)用場(chǎng)景(如聊天應(yīng)用、實(shí)時(shí)數(shù)據(jù)監(jiān)控等)非常有用。(服務(wù)端單向傳輸客戶端,長(zhǎng)連接)
主要特點(diǎn):
- 單向通信:數(shù)據(jù)從服務(wù)器流向客戶端,客戶端不能直接向服務(wù)器發(fā)送數(shù)據(jù)。
- 基于HTTP:SSE使用HTTP協(xié)議,簡(jiǎn)單易用,支持瀏覽器。
- 自動(dòng)重連:如果連接丟失,瀏覽器會(huì)自動(dòng)嘗試重連。
- 文本格式:數(shù)據(jù)以文本流的形式發(fā)送,通常是UTF-8編碼。
使用場(chǎng)景:頻繁的更新數(shù)據(jù),低延遲,單向通信
二.SSE的實(shí)現(xiàn)過(guò)程:
首先前端給后端發(fā)送請(qǐng)求,隨后后端會(huì)返回響應(yīng)文本流創(chuàng)建連接,然后后端就可以持續(xù)的長(zhǎng)連接進(jìn)行給前端傳輸數(shù)據(jù)。
SSE 基于 HTTP 協(xié)議,利用了其長(zhǎng)連接特性,通過(guò)瀏覽器向服務(wù)器發(fā)送一個(gè) HTTP 請(qǐng)求,建立一條持久化的連接。SSE 可以傳輸文本和二進(jìn)制格式的數(shù)據(jù),但只支持單向數(shù)據(jù)流,即只能由服務(wù)器向客戶端推送數(shù)據(jù)。
三.SSE的前端實(shí)現(xiàn):
1.創(chuàng)建 EventSource 對(duì)象:
通過(guò)指定服務(wù)器端的SSE URL,創(chuàng)建一個(gè)
EventSource
實(shí)例。
const eventSource = new EventSource('http://localhost:8080/sse/chat');
2.處理接收到的信息:
使用
onmessage
事件處理程序接收服務(wù)器發(fā)送的消息。
eventSource.onmessage = function(event) { console.log('Received:', event.data); // 在這里處理接收到的數(shù)據(jù),比如更新UI };
接收到的event
是一個(gè)MessageEvent
對(duì)象,它包含以下重要屬性:
data
:這是服務(wù)器發(fā)送的消息內(nèi)容,通常是文本或JSON字符串。origin
:表示事件來(lái)源的URI,通常是服務(wù)器的URL。lastEventId
:如果瀏覽器重新連接,它會(huì)包含最后接收到的事件ID,這在處理丟失消息時(shí)非常有用。
eventSource.onmessage = function(event) { // event.data的結(jié)果假設(shè)是 '{"name": "Alice", "age": 25}' console.log('Received:', event.data); // 如果是JSON格式,解析后 message 是一個(gè)對(duì)象: { name: "Alice", age: 25 } const message = JSON.parse(event.data); // 在這里更新UI或進(jìn)行其他操作 };
SSE發(fā)送的數(shù)據(jù)是以文本流的形式傳輸?shù)?,通常是字符串(例如,JSON格式的字符串)。如果服務(wù)器發(fā)送的是JSON格式的字符串(例如 {"key": "value"}
),那么你可以使用 JSON.parse()
將這個(gè)字符串轉(zhuǎn)換為JavaScript對(duì)象,以便更方便地訪問(wèn)數(shù)據(jù)。
3.處理特定事件:
如果服務(wù)器發(fā)送了不同類型的事件,可以使用
oneventname
處理特定事件。
eventSource.addEventListener('customEvent', function(event) { console.log('Custom event received:', event.data); });
4.處理連接錯(cuò)誤問(wèn)題:
可以使用
onerror
事件處理程序來(lái)處理連接錯(cuò)誤。
eventSource.onerror = function(event) { console.error('EventSource failed:', event); // 可以在這里實(shí)現(xiàn)重連邏輯 };
5.關(guān)閉連接:
如果不再需要接收消息,可以通過(guò)調(diào)用
close
方法來(lái)關(guān)閉連接。
eventSource.close();
四.SSE的后端實(shí)現(xiàn):
1.導(dǎo)入web依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2.創(chuàng)建Controller類:
package com.itheima.bigdealboot.controller; import lombok.extern.slf4j.Slf4j; 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.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @RestController @RequestMapping("/sse") @Slf4j public class SSEController { @GetMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter sseChat(){ SseEmitter emitter = new SseEmitter(); // 創(chuàng)建一個(gè)定時(shí)任務(wù) ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(() -> { try { // 發(fā)送當(dāng)前時(shí)間戳 emitter.send(System.currentTimeMillis()); } catch (IOException e) { // 處理異常(如客戶端關(guān)閉連接) emitter.completeWithError(e); } }, 0, 1, TimeUnit.SECONDS); // 每秒發(fā)送一次 // 處理連接關(guān)閉 emitter.onCompletion(() -> executor.shutdown()); emitter.onTimeout(() -> { emitter.complete(); executor.shutdown(); }); return emitter; // 返回SseEmitter實(shí)例 } }
- SseEmitter實(shí)例:創(chuàng)建
SseEmitter
對(duì)象,準(zhǔn)備向前端發(fā)送事件。 - 定時(shí)任務(wù):使用
ScheduledExecutorService
定期發(fā)送數(shù)據(jù)(如當(dāng)前時(shí)間戳)。如果發(fā)送失?。ɡ纾蛻舳岁P(guān)閉連接),則調(diào)用completeWithError()
處理異常。 - 連接關(guān)閉處理:
onCompletion()
:當(dāng)連接正常關(guān)閉時(shí)調(diào)用,執(zhí)行資源清理。onTimeout()
:在連接超時(shí)時(shí)關(guān)閉連接。
3.SeeEmitter的介紹以及使用方法:
SseEmitter
是 Spring框架提供的一個(gè)類,用于支持 Server-Sent Events (SSE)。
(1). 構(gòu)造方法
SseEmitter()
:創(chuàng)建一個(gè)新的SseEmitter
實(shí)例,使用默認(rèn)的超時(shí)值。SseEmitter(Long timeout)
:創(chuàng)建一個(gè)新的SseEmitter
實(shí)例,設(shè)置指定的超時(shí)時(shí)間(毫秒)。
(2). 發(fā)送數(shù)據(jù)
send(Object data)
:發(fā)送數(shù)據(jù)到客戶端。send(Object data, MediaType mediaType)
:發(fā)送數(shù)據(jù)到客戶端,并指定數(shù)據(jù)的媒體類型。send(SseEvent event)
:發(fā)送一個(gè)SseEvent
對(duì)象到客戶端。
(3). 關(guān)閉連接
complete()
:正常完成事件流,關(guān)閉連接。completeWithError(Throwable throwable)
:由于錯(cuò)誤完成事件流,并關(guān)閉連接。completeWithError(String message)
:由于錯(cuò)誤完成事件流,并關(guān)閉連接,提供錯(cuò)誤信息。
(4). 連接狀態(tài)處理
onCompletion(Runnable callback)
:注冊(cè)連接完成的回調(diào)函數(shù)。onTimeout(Runnable callback)
:注冊(cè)連接超時(shí)的回調(diào)函數(shù)。
(5). 獲取超時(shí)時(shí)間
getTimeout()
:返回當(dāng)前的超時(shí)時(shí)間(毫秒)。
(6). 其他
isCompleted()
:檢查SseEmitter
是否已完成。isExpired()
:檢查SseEmitter
是否已過(guò)期。
總結(jié)
到此這篇關(guān)于使用SSE流式輸出(Javaweb前后端)的文章就介紹到這了,更多相關(guān)Javaweb前后端SSE流式輸出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot validator參數(shù)驗(yàn)證restful自定義錯(cuò)誤碼響應(yīng)方式
這篇文章主要介紹了SpringBoot validator參數(shù)驗(yàn)證restful自定義錯(cuò)誤碼響應(yīng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10如何通過(guò)properties文件配置web.xml中的參數(shù)
這篇文章主要介紹了如何通過(guò)properties文件配置web.xml中的參數(shù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08解決dubbo注冊(cè)到zookeeper速度慢的問(wèn)題
這篇文章主要介紹了解決dubbo注冊(cè)到zookeeper速度慢的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04Java代碼實(shí)現(xiàn)簡(jiǎn)單酒店管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java代碼實(shí)現(xiàn)簡(jiǎn)單酒店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06SpringMvc web.xml配置實(shí)現(xiàn)原理過(guò)程解析
這篇文章主要介紹了SpringMvc web.xml配置實(shí)現(xiàn)原理過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08