Spring Boot 二三事:WEB 应用消息推送的那点事

本文介绍了在Spring Boot中实现WEB应用消息推送的两种方法:Server-Sent Events (SSE) 和 WebSocket。详细讲解了SSE的特性与Spring Boot中使用SSE的步骤,以及WebSocket的基本概念和Spring WebSocket的低级API与STOMP高级API的使用。通过一个下载文件的案例,演示了SSE和WebSocket的推送过程,总结了各种推送方式的适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

阅读对象:本文适合SpringBoot 初学者及对SpringBoot感兴趣的童鞋阅读。

背景介绍:在企业级 WEB 应用开发中,为了更好的用户体验&提升响应速度,往往会将一些耗时费力的请求 (Excel导入or导出,复杂计算, etc.) 进行***异步化***处理。 由此带来的一个重要的问题是***如何通知用户任务状态***,常见的方法大致分为2类4种:

  • HTTP Pollingclient pull
  • HTTP Long-Pollingclient pull
  • Server-Sent Events (SSE)server push
  • WebSocketserver push
1. Polling 短轮询

是一种非常简单的实现方式。就是client通过***定时任务***不断得重复请求服务器,从而获取新消息,而server按时间顺序提供自上次请求以后发生的单个或多个消息。

Polling

短轮询的优点非常明显,就是实现简单。当两个方向上的数据都非常少,并且请求间隔不是非常密集时,这种方法就会非常有效。例如,新闻评论信息可以每半分钟更新一次,这对用户来说是可以的。

它得缺点也是非常明显,一旦我们对数据实时性要求非常高时,为了保证消息的及时送达,请求间隔必须缩短,在这种情况下,会加剧服务器资源的浪费,降低服务的可用性。另一个缺点就是在消息的数量较少时,将会有大量的 request做无用功,进而也导致服务器资源的浪费。

2. Long-Polling 长轮询

长轮询的官方定义是:

The server attempts to “hold open” (notimmediately reply to) each HTTP request, responding only when there are events to deliver. In this way, there is always a pending request to which the server can reply for the purpose of delivering events as they occur, thereby minimizing the latency in message delivery.

如果与Polling的方式相比,会发现Long-Polling的优点是通过hold open HTTP request 从而减少了无用的请求。

大致步骤为:

  1. client向server请求并等待响应。
  2. 服务端将请求阻塞,并不断检查是否有新消息。如果在这个期间有新消息产生时就立即返回。否则一直等待至请求超时
  3. 当client 获取到新消息请求超时,进行消息处理并发起下一次请求。

Long Polling

Long-Polling的缺点之一也是服务器资源的浪费,因为它和Polling的一样都属于***被动获取***,都需要不断的向服务器请求。在并发很高的情况下,对服务器性能是个严峻的考验。

Note:因为以上2两种方式的实现都比较简单,所以我们这里就不做代码演示了。接下来我们重点介绍一下Server-Sent EventsWebSocket

3. Demo概要

下面我们将通过一个***下载文件***的案例进行演示SSEWebSocket的消息推送,在这之前,我们先简单说一下我们项目的结构,整个项目基于SpringBoot 构建。

首先我们定义一个供前端访问的APIDownloadController

@RestController
public class DownloadController {
   
   
    private static final Logger log = getLogger(DownloadController.class);
    @Autowired
    private MockDownloadComponent downloadComponent;  

    @GetMapping("/api/download/{type}")
    public String download(@PathVariable String type, HttpServletRequest request) {
   
     // (A)
        HttpSession session = request.getSession();
        String sessionid = session.getId();
        log.info("sessionid=[{}]", sessionid);
        downloadComponent.mockDownload(type, sessionid);  // (B)
        return "success"; // (C)
    }
}
  • (A) type参数用于区分使用哪种推送方式,这里为sse,ws,stomp这三种类型。
  • (B) MockDownloadComponent用于异步模拟下载文件的过程。
  • © 因为下载过程为异步化,所以该方法不会被阻塞并立即向客户端返回success,用于表明下载开始

DownloadController中我们调用MockDownloadComponentmockDownload()的方法进行模拟真正的下载逻辑。

@Component
public class MockDownloadComponent {
   
   
    private static final Logger log = LoggerFactory.getLogger(DownloadController.class);

    @Async // (A)
    public void mockDownload(String type, String sessionid) {
   
   
        for (int i = 0; i < 100; i  ) {
   
   
            try {
   
   
                TimeUnit.MILLISECONDS.sleep(100); // (B)

                int percent = i   1;
                String content = String.format("{\"username\":\"%s\",\"percent\":%d}", sessionid, percent); // (C)
                log.info("username={}'s file has been finished [{}]% ", sessionid, percent);

                switch (type) {
   
    // (D)
                    case "sse":
                        SseNotificationController.usesSsePush(sessionid, content);
                        break;
                    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值