SpringBoot环境下服务端向客户端主动推送数据的几种常见方式

 更新时间:2025年07月09日 09:05:50   作者:超级小忍  
在传统的 HTTP 请求-响应模型中,客户端需要主动发起请求,服务端才能返回数据,然而,在某些场景下,我们希望服务端能够主动向客户端推送数据,本文将详细介绍在 Spring Boot 环境下实现服务端向客户端主动推送数据的几种常见方式,并比较它们的优缺点和适用场景

前言

在传统的 HTTP 请求-响应模型中,客户端需要主动发起请求,服务端才能返回数据。然而,在某些场景下(如实时聊天、股票行情更新、通知系统等),我们希望服务端能够主动向客户端推送数据。本文将详细介绍在 Spring Boot 环境下实现服务端向客户端主动推送数据的几种常见方式,并比较它们的优缺点和适用场景。

一、什么是“服务端推送”?

“服务端推送”是指服务端在没有收到客户端请求的情况下,主动将数据发送给客户端。这种机制打破了传统 HTTP 的单向通信限制,适用于需要实时交互的场景。

二、常用推送技术概述

以下是目前主流的几种服务端向客户端推送数据的方式:

  1. 长轮询(Long Polling)
  2. Server-Sent Events(SSE)
  3. WebSocket
  4. MQTT(物联网常用)
  5. 基于消息中间件 + 客户端监听(如 RabbitMQ + STOMP)

本文主要聚焦于前三种与 Spring Boot 集成较为方便的技术。

三、方法一:长轮询(Long Polling)

1. 原理简介

客户端定时或持续发起请求到服务端,服务端如果无新数据则保持连接不返回,直到有数据或超时后才响应。客户端收到响应后立即发起下一次请求。

2. 优点

  • 兼容性好,支持所有浏览器
  • 实现简单,适合小型项目或低频更新

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); // 模拟等待新数据
        }
        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() // 继续下一次轮询
    })
}

startPolling()

四、方法二:Server-Sent Events(SSE)

1. 原理简介

SSE 是 HTML5 提供的一种服务器向客户端推送事件的标准协议。它是单向通信,即服务端可以不断向客户端发送数据,但客户端不能通过该通道向服务端发送数据。

2. 优点

  • 实时性强
  • 协议轻量,易于实现
  • 支持自动重连

3. 缺点

  • 只能服务端推送送,不支持双向通信
  • 不兼容 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 是一种全双工通信协议,允许服务端和客户端之间建立持久连接并随时互相发送数据。是目前最强大的实时通信解决方案之一。

2. 优点

  • 实时性强,延迟低
  • 支持双向通信
  • 数据传输效率高

3. 缺点

  • 实现相对复杂
  • 需要客户端和服务端都支持 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. 发送消息的 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(适用于物联网场景)

  • 轻量级发布/订阅协议
  • 适用于设备间通信
  • 可以结合 Spring Boot + EMQX / Mosquitto 使用

2. 消息队列 + 客户端监听(如 RabbitMQ)

  • 服务端将数据发到 MQ
  • 客户端监听某个队列或 Exchange
  • 适合解耦和分布式系统架构

七、对比总结表

方法通信方向是否实时是否双向易用性适用场景
长轮询单向否(延迟高)简单简单场景、兼容性要求高
SSE单向较简单实时数据展示(如新闻、监控)
WebSocket双向非常实时较复杂聊天、协同编辑、游戏等
MQTT双向非常实时较复杂物联网、低带宽环境
消息队列 + 监听双向非常实时较复杂分布式系统、微服务

八、如何选择合适的方法?

根据以下因素进行权衡:

  • 是否需要双向通信?
  • 对实时性的要求有多高?
  • 客户端是否支持新技术(如 WebSocket)?
  • 是否有资源限制(如移动端、IoT 设备)?
  • 是否已有消息中间件?

九、结语

随着 Web 技术的发展,服务端主动推送数据已经不再是难题。Spring Boot 提供了丰富的组件来支持各种推送方式。开发者应根据业务需求、性能考量以及技术栈特点,选择最适合的推送方案。

如果你正在开发一个实时性要求高的应用,推荐优先考虑 WebSocket;如果是简单的数据流推送,可以尝试 SSE;而如果必须支持老旧浏览器或低频更新,长轮询仍然是一个可行的选择。

以上就是SpringBoot环境下服务端向客户端主动推送数据的几种常见方式的详细内容,更多关于SpringBoot服务端向客户端推送数据的资料请关注脚本之家其它相关文章!

相关文章

  • Spring MVC各种参数进行封装的方法实例

    Spring MVC各种参数进行封装的方法实例

    这篇文章主要给大家介绍了关于Spring MVC各种参数进行封装的相关资料,SpringMVC内置多种数据类型转换器,可以根据请求中的参数与后端控制器方法的参数的关系为我们实现简单的数据封装,需要的朋友可以参考下
    2023-06-06
  • 详解springboot整合Listener的两种方式

    详解springboot整合Listener的两种方式

    这篇文章主要介绍了springboot整合Listener的两种方式,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-12-12
  • 一文详解各种ElasticSearch查询在Java中的实现

    一文详解各种ElasticSearch查询在Java中的实现

    Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎,下面这篇文章主要给大家介绍了关于各种ElasticSearch查询在Java中实现的相关资料,需要的朋友可以参考下
    2023-11-11
  • java WSDL接口webService实现方式

    java WSDL接口webService实现方式

    这篇文章主要为大家详细介绍了java WSDL接口webService实现方式的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 我从jdk1.8升级到jdk11所遇到的坑都有这些

    我从jdk1.8升级到jdk11所遇到的坑都有这些

    这篇文章主要介绍了从jdk1.8升级到jdk11将会遇到的一些坑,本文给大家分享解决方案对大家的学习或工作具有参考借鉴价值,对jdk1.8升级到jdk11相关知识感兴趣的朋友,快来看看吧
    2021-08-08
  • Spring容器中添加bean的5种方式

    Spring容器中添加bean的5种方式

    我们知道平时在开发中使用Spring的时候,都是将对象交由Spring去管理,那么将一个对象加入到Spring容器中,有哪些方式呢,感兴趣的可以了解一下
    2021-07-07
  • SpringBoot整合Redis实现消息发布与订阅的示例代码

    SpringBoot整合Redis实现消息发布与订阅的示例代码

    能实现发送与接收信息的中间介有很多,比如:RocketMQ、RabbitMQ、ActiveMQ、Kafka等,本文主要介绍了Redis的推送与订阅功能并集成Spring Boot的实现,感兴趣的可以了解一下
    2022-08-08
  • Java微信公众平台开发(12) 微信用户信息的获取

    Java微信公众平台开发(12) 微信用户信息的获取

    这篇文章主要为大家详细介绍了Java微信公众平台开发第十二步,微信用户信息的获取,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • 基于java实现一个脱敏组件

    基于java实现一个脱敏组件

    这篇文章主要为大家详细介绍了如何基于java实现一个脱敏组件,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-11-11
  • Spring Security基本原理详解

    Spring Security基本原理详解

    这篇文章主要介绍了Spring Security基本原理详解,springsecurity底层实现为一条过滤器链,就是用户请求进来,判断有没有请求的权限,抛出异常,重定向跳转,需要的朋友可以参考下
    2023-05-05

最新评论