SpringBoot環(huán)境下服務(wù)端向客戶端主動推送數(shù)據(jù)的幾種常見方式
前言
在傳統(tǒng)的 HTTP 請求-響應(yīng)模型中,客戶端需要主動發(fā)起請求,服務(wù)端才能返回數(shù)據(jù)。然而,在某些場景下(如實時聊天、股票行情更新、通知系統(tǒng)等),我們希望服務(wù)端能夠主動向客戶端推送數(shù)據(jù)。本文將詳細(xì)介紹在 Spring Boot 環(huán)境下實現(xiàn)服務(wù)端向客戶端主動推送數(shù)據(jù)的幾種常見方式,并比較它們的優(yōu)缺點和適用場景。
一、什么是“服務(wù)端推送”?
“服務(wù)端推送”是指服務(wù)端在沒有收到客戶端請求的情況下,主動將數(shù)據(jù)發(fā)送給客戶端。這種機(jī)制打破了傳統(tǒng) HTTP 的單向通信限制,適用于需要實時交互的場景。
二、常用推送技術(shù)概述
以下是目前主流的幾種服務(wù)端向客戶端推送數(shù)據(jù)的方式:
- 長輪詢(Long Polling)
- Server-Sent Events(SSE)
- WebSocket
- MQTT(物聯(lián)網(wǎng)常用)
- 基于消息中間件 + 客戶端監(jiān)聽(如 RabbitMQ + STOMP)
本文主要聚焦于前三種與 Spring Boot 集成較為方便的技術(shù)。
三、方法一:長輪詢(Long Polling)
1. 原理簡介
客戶端定時或持續(xù)發(fā)起請求到服務(wù)端,服務(wù)端如果無新數(shù)據(jù)則保持連接不返回,直到有數(shù)據(jù)或超時后才響應(yīng)??蛻舳耸盏巾憫?yīng)后立即發(fā)起下一次請求。
2. 優(yōu)點
- 兼容性好,支持所有瀏覽器
- 實現(xiàn)簡單,適合小型項目或低頻更新
3. 缺點
- 連接頻繁建立銷毀,資源消耗大
- 推送延遲較高
4. Spring Boot 示例代碼
Controller 層
@RestController
public class LongPollingController {
private String latestData = "No new data";
@GetMapping("/poll")
public String poll(@RequestParam String clientId) throws InterruptedException {
synchronized (this) {
wait(10000); // 模擬等待新數(shù)據(jù)
}
return latestData;
}
@PostMapping("/update")
public void updateData(@RequestBody Map<String, String> payload) {
this.latestData = payload.get("data");
synchronized (this) {
notifyAll(); // 通知所有等待線程
}
}
}
客戶端模擬(JavaScript)
function startPolling() {
fetch("/poll?clientId=1")
.then((res) => res.text())
.then((data) => {
console.log("Received:", data)
startPolling() // 繼續(xù)下一次輪詢
})
}
startPolling()
四、方法二:Server-Sent Events(SSE)
1. 原理簡介
SSE 是 HTML5 提供的一種服務(wù)器向客戶端推送事件的標(biāo)準(zhǔn)協(xié)議。它是單向通信,即服務(wù)端可以不斷向客戶端發(fā)送數(shù)據(jù),但客戶端不能通過該通道向服務(wù)端發(fā)送數(shù)據(jù)。
2. 優(yōu)點
- 實時性強(qiáng)
- 協(xié)議輕量,易于實現(xiàn)
- 支持自動重連
3. 缺點
- 只能服務(wù)端推送送,不支持雙向通信
- 不兼容 IE 瀏覽器
4. Spring Boot 示例代碼
Controller 層
@RestController
public class SseController {
private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>();
@GetMapping("/subscribe")
public SseEmitter subscribe() {
SseEmitter emitter = new SseEmitter(60_000L); // 超時時間
emitters.add(emitter);
emitter.onCompletion(() -> emitters.remove(emitter));
return emitter;
}
@PostMapping("/send")
public void sendData(@RequestBody Map<String, String> payload) {
String message = payload.get("message");
emitters.forEach(emitter -> {
try {
emitter.send(message);
} catch (IOException e) {
emitter.complete();
emitters.remove(emitter);
}
});
}
}
客戶端代碼(HTML + JavaScript)
<script>
const eventSource = new EventSource("/subscribe")
eventSource.onmessage = function (event) {
console.log("New message:", event.data)
}
eventSource.onerror = function (err) {
console.error("EventSource failed:", err)
}
</script>
五、方法三:WebSocket
1. 原理簡介
WebSocket 是一種全雙工通信協(xié)議,允許服務(wù)端和客戶端之間建立持久連接并隨時互相發(fā)送數(shù)據(jù)。是目前最強(qiáng)大的實時通信解決方案之一。
2. 優(yōu)點
- 實時性強(qiáng),延遲低
- 支持雙向通信
- 數(shù)據(jù)傳輸效率高
3. 缺點
- 實現(xiàn)相對復(fù)雜
- 需要客戶端和服務(wù)端都支持 WebSocket
- 部分防火墻或代理可能不支持
4. Spring Boot 示例代碼
1. 添加依賴(pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 配置 WebSocket
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
3. 發(fā)送消息的 Controller
@Controller
public class WsController {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@PostMapping("/broadcast")
public void broadcast(@RequestBody Map<String, String> payload) {
String message = payload.get("message");
messagingTemplate.convertAndSend("/topic/messages", message);
}
}
4. 客戶端代碼(使用 SockJS + Stomp.js)
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stompjs/lib/stomp.min.js"></script>
<script>
const socket = new SockJS("/ws")
const stompClient = Stomp.over(socket)
stompClient.connect({}, () => {
stompClient.subscribe("/topic/messages", (msg) => {
console.log("Received:", msg.body)
})
})
</script>
六、其他方式簡要介紹
1. MQTT(適用于物聯(lián)網(wǎng)場景)
- 輕量級發(fā)布/訂閱協(xié)議
- 適用于設(shè)備間通信
- 可以結(jié)合 Spring Boot + EMQX / Mosquitto 使用
2. 消息隊列 + 客戶端監(jiān)聽(如 RabbitMQ)
- 服務(wù)端將數(shù)據(jù)發(fā)到 MQ
- 客戶端監(jiān)聽某個隊列或 Exchange
- 適合解耦和分布式系統(tǒng)架構(gòu)
七、對比總結(jié)表
| 方法 | 通信方向 | 是否實時 | 是否雙向 | 易用性 | 適用場景 |
|---|---|---|---|---|---|
| 長輪詢 | 單向 | 否(延遲高) | 否 | 簡單 | 簡單場景、兼容性要求高 |
| SSE | 單向 | 是 | 否 | 較簡單 | 實時數(shù)據(jù)展示(如新聞、監(jiān)控) |
| WebSocket | 雙向 | 非常實時 | 是 | 較復(fù)雜 | 聊天、協(xié)同編輯、游戲等 |
| MQTT | 雙向 | 非常實時 | 是 | 較復(fù)雜 | 物聯(lián)網(wǎng)、低帶寬環(huán)境 |
| 消息隊列 + 監(jiān)聽 | 雙向 | 非常實時 | 是 | 較復(fù)雜 | 分布式系統(tǒng)、微服務(wù) |
八、如何選擇合適的方法?
根據(jù)以下因素進(jìn)行權(quán)衡:
- 是否需要雙向通信?
- 對實時性的要求有多高?
- 客戶端是否支持新技術(shù)(如 WebSocket)?
- 是否有資源限制(如移動端、IoT 設(shè)備)?
- 是否已有消息中間件?
九、結(jié)語
隨著 Web 技術(shù)的發(fā)展,服務(wù)端主動推送數(shù)據(jù)已經(jīng)不再是難題。Spring Boot 提供了豐富的組件來支持各種推送方式。開發(fā)者應(yīng)根據(jù)業(yè)務(wù)需求、性能考量以及技術(shù)棧特點,選擇最適合的推送方案。
如果你正在開發(fā)一個實時性要求高的應(yīng)用,推薦優(yōu)先考慮 WebSocket;如果是簡單的數(shù)據(jù)流推送,可以嘗試 SSE;而如果必須支持老舊瀏覽器或低頻更新,長輪詢仍然是一個可行的選擇。
以上就是SpringBoot環(huán)境下服務(wù)端向客戶端主動推送數(shù)據(jù)的幾種常見方式的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot服務(wù)端向客戶端推送數(shù)據(jù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring?MVC各種參數(shù)進(jìn)行封裝的方法實例
這篇文章主要給大家介紹了關(guān)于Spring?MVC各種參數(shù)進(jìn)行封裝的相關(guān)資料,SpringMVC內(nèi)置多種數(shù)據(jù)類型轉(zhuǎn)換器,可以根據(jù)請求中的參數(shù)與后端控制器方法的參數(shù)的關(guān)系為我們實現(xiàn)簡單的數(shù)據(jù)封裝,需要的朋友可以參考下2023-06-06
一文詳解各種ElasticSearch查詢在Java中的實現(xiàn)
Elasticsearch是用Java開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是當(dāng)前流行的企業(yè)級搜索引擎,下面這篇文章主要給大家介紹了關(guān)于各種ElasticSearch查詢在Java中實現(xiàn)的相關(guān)資料,需要的朋友可以參考下2023-11-11
java WSDL接口webService實現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了java WSDL接口webService實現(xiàn)方式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04
我從jdk1.8升級到j(luò)dk11所遇到的坑都有這些
這篇文章主要介紹了從jdk1.8升級到j(luò)dk11將會遇到的一些坑,本文給大家分享解決方案對大家的學(xué)習(xí)或工作具有參考借鑒價值,對jdk1.8升級到j(luò)dk11相關(guān)知識感興趣的朋友,快來看看吧2021-08-08
SpringBoot整合Redis實現(xiàn)消息發(fā)布與訂閱的示例代碼
能實現(xiàn)發(fā)送與接收信息的中間介有很多,比如:RocketMQ、RabbitMQ、ActiveMQ、Kafka等,本文主要介紹了Redis的推送與訂閱功能并集成Spring Boot的實現(xiàn),感興趣的可以了解一下2022-08-08
Java微信公眾平臺開發(fā)(12) 微信用戶信息的獲取
這篇文章主要為大家詳細(xì)介紹了Java微信公眾平臺開發(fā)第十二步,微信用戶信息的獲取,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04

