在 Spring Boot 中实现服务器端推送(SSE):两种方法的比较与实践 ...

打印 上一主题 下一主题

主题 1659|帖子 1659|积分 4977

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在现代 Web 应用中,及时数据推送是一个常见的需求。无论是及时消息通知、股票行情更新,照旧在线游戏的及时数据交互,服务器端推送(Server-Sent Events,简称 SSE)都是一种高效且易于实现的解决方案。在 Spring Boot 中,有两种主要方式可以实现 SSE:使用 SseEmitter 和使用 Spring WebFlux。本文将具体介绍这两种方法的实现步骤,并比较它们的优缺点,资助你在实际开辟中选择符合的技能方案。
一、什么是 Server-Sent Events(SSE)

Server-Sent Events 是一种允许服务器向客户端推送及时更新的技能。与传统的轮询或长轮询相比,SSE 提供了一种更高效、更轻量级的解决方案。SSE 使用 HTTP 协议,客户端通过一个简单的 EventSource 接口订阅服务器端的事件流,服务器端则通过持续的 HTTP 连接向客户端发送数据。
SSE 的主要特点包罗:


  • 单向通信:数据从服务器流向客户端。
  • 轻量级:基于 HTTP,不需要额外的 WebSocket 协议支持。
  • 自动重连:客户端在连接断开后会自动实行重新连接。
  • 跨浏览器支持:现代浏览器广泛支持 SSE。
二、使用 SseEmitter 实现 SSE

SseEmitter 是 Spring 提供的一个工具类,用于实现 SSE。它允许你手动管理每个客户端的连接,并向它们推送数据。
1. 添加依赖

确保你的 Spring Boot 项目中包含以下依赖:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
复制代码
2. 创建控制器

创建一个控制器来管理 SSE 连接和推送消息:
  1. import org.springframework.http.MediaType;
  2. import org.springframework.web.bind.annotation.*;
  3. import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
  4. import java.io.IOException;
  5. import java.util.Collections;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. import java.util.concurrent.CopyOnWriteArrayList;
  9. @RestController
  10. public class SSEController {
  11.     private final Map<String, SseEmitter> emitters = Collections.synchronizedMap(new HashMap<>());
  12.     @GetMapping("/sse/connect/{clientId}")
  13.     public SseEmitter connect(@PathVariable String clientId) {
  14.         SseEmitter emitter = new SseEmitter();
  15.         emitters.put(clientId, emitter);
  16.         emitter.onCompletion(() -> emitters.remove(clientId));
  17.         emitter.onTimeout(() -> emitters.remove(clientId));
  18.         emitter.onError(e -> emitters.remove(clientId));
  19.         return emitter;
  20.     }
  21.     @GetMapping("/sse/send/{clientId}")
  22.     public void sendMessage(@PathVariable String clientId) {
  23.         SseEmitter emitter = emitters.get(clientId);
  24.         if (emitter != null) {
  25.             try {
  26.                 emitter.send(SseEmitter.event().data("Hello, client " + clientId + "!"));
  27.             } catch (IOException e) {
  28.                 emitter.completeWithError(e);
  29.             }
  30.         }
  31.     }
  32. }
复制代码
3. 前端实现

在前端页面中,使用 EventSource 来订阅 SSE:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>SSE Example</title>
  6. </head>
  7. <body>
  8. <div id="messages"></div>
  9. <script>
  10.     const eventSource = new EventSource('/sse/connect/client1');
  11.     eventSource.onmessage = function(event) {
  12.         const messagesDiv = document.getElementById('messages');
  13.         const newMessage = document.createElement('p');
  14.         newMessage.textContent = event.data;
  15.         messagesDiv.appendChild(newMessage);
  16.     };
  17.     eventSource.onerror = function(err) {
  18.         console.error("Error:", err);
  19.         eventSource.close();
  20.     };
  21. </script>
  22. </body>
  23. </html>
复制代码
三、使用 Spring WebFlux 实现 SSE

Spring WebFlux 提供了更简洁的方式来实现 SSE,使用相应式编程模子。
1. 添加依赖

确保你的项目中包含 WebFlux 依赖:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-webflux</artifactId>
  4. </dependency>
复制代码
2. 创建控制器

使用 Flux 来天生数据流:
  1. import org.springframework.http.MediaType;
  2. import org.springframework.web.bind.annotation.GetMapping;
  3. import org.springframework.web.bind.annotation.RestController;
  4. import reactor.core.publisher.Flux;
  5. import java.time.Duration;
  6. import java.time.LocalTime;
  7. @RestController
  8. public class FluxController {
  9.     @GetMapping(value = "/stream/time", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  10.     public Flux<String> streamTime() {
  11.         return Flux.interval(Duration.ofSeconds(1))
  12.                 .map(sequence -> "Current Time: " + LocalTime.now());
  13.     }
  14. }
复制代码
3. 前端实现

前端代码与使用 SseEmitter 的实现类似,使用 EventSource 来订阅数据流:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>SSE Time Stream</title>
  6. </head>
  7. <body>
  8. <h1>实时推送当前时间</h1>
  9. <ul id="time-list"></ul>
  10. <script>
  11.     const eventSource = new EventSource('/stream/time');
  12.     eventSource.onmessage = function(event) {
  13.         const timeList = document.getElementById('time-list');
  14.         const listItem = document.createElement('li');
  15.         listItem.textContent = event.data;
  16.         timeList.appendChild(listItem);
  17.     };
  18.     eventSource.onerror = function(error) {
  19.         console.error('Error:', error);
  20.         eventSource.close();
  21.     };
  22. </script>
  23. </body>
  24. </html>
复制代码
四、两种方法的比较

1. 灵活性



  • SseEmitter:提供了更高的灵活性,允许你手动管理每个客户端的连接,适合需要对每个客户端举行风雅控制的场景。
  • Spring WebFlux:更适合天生连续的数据流,代码更简洁,适合相应式编程场景。
2. 性能



  • SseEmitter:基于传统的 Spring MVC,适合处理少量客户端连接。
  • Spring WebFlux:基于相应式编程模子,适合处理大量并发连接,性能更高。
3. 易用性



  • SseEmitter:代码相对复杂,需要手动管理连接和错误处理。
  • Spring WebFlux:代码更简洁,使用 Flux 和 Mono 提供了更强大的功能。
五、总结

在 Spring Boot 中实现 SSE 有多种方式,选择哪种方式取决于你的具体需求。如果你需要对每个客户端举行风雅控制,SseEmitter 是一个不错的选择。如果你需要处理大量并发连接,或者希望代码更简洁,Spring WebFlux 是一个更好的选择。
希望本文能资助你在实际开辟中更好地实现 SSE,为你的应用带来更及时、更高效的用户体验。
参考资料



  • 如何使用Spring Boot Webflux优雅实现数据流的SSE推送?
  • Spring boot还在使用websocket推数据?快来试试SSE吧
  • Spring Boot 整合 SSE(Server-Sent Events) - CSDN博客
  • Spring 中 Server-Sent Events(SSE)消息推送实现
  • SpringBoot + SSE 及时异步流式推送
  • Spring Boot + SSE 打造及时消息推送 | SSN
如果你有任何题目或建议,请随时在评论区留言,我会尽快回复。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

玛卡巴卡的卡巴卡玛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表