重学SpringBoot3-Spring WebFlux之SSE服务器发送事件

SSE接口的几种实现方式 我会在本章介绍SSE接口的几种实现方式,包括webflux和spring mvc,以及使用几种方法调用sse接口的方法。 阅读详情
AI摘要

本文围绕Spring Boot 3中SSE服务器发送事件展开。介绍了SSE概念、特点及与WebSocket对比,阐述Spring Boot 3响应式编程适合实现SSE的原因。详细说明了实现SSE的基本步骤,包括创建项目、服务端推送、客户端接收等,还提及测试、优化扩展方法,展示了其在实时数据推送中的优势。

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞??收藏评论

在这里插入图片描述

Spring WebFlux之SSE服务器发送事件

ChatGPT 刚出的时候,让大伙很好奇的是它是如何实现的逐字输出的?答案就是 SSE (服务器发送事件)。随着实时数据和响应式编程的需求不断增加,服务器发送事件(Server-Sent Events,简称 SSE)在现代 Web 应用程序中越来越受欢迎。SSE 提供了一种轻量级的服务器推送数据给客户端的方式,适合用于监控、实时通知、股票价格更新等场景。

在 Spring Boot 3 中,结合响应式编程的理念,SSE 的实现变得更加简洁和高效。本文将详细介绍如何使用 Spring Boot 3 来实现 SSE 服务端推送,并讨论响应式编程在此过程中的重要性和优势。

1. 什么是 SSE?

服务器发送事件(SSE) 是一种从服务器向客户端推送数据的技术,属于 HTML5 的一部分。与传统的 HTTP 请求-响应模型不同,SSE 是单向的,服务器可以持续不断地向客户端发送数据,而客户端通过一次长连接持续接收这些更新。

相比 WebSocket,SSE 有以下特点:

  • 单向通信:SSE 仅允许服务器向客户端推送数据,客户端无法向服务器发送数据。
  • 基于 HTTP 协议:SSE 是建立在 HTTP 协议之上的,浏览器原生支持,不需要额外的协议处理。
  • 自动重连:SSE 支持自动重连,当连接意外断开时,客户端会自动尝试重新连接服务器。

2. Spring Boot 3 响应式编程与 SSE

Spring Boot 3 提供了对响应式编程的全面支持,基于 Project Reactor 实现异步、非阻塞的流式数据处理。而响应式编程非常适合实现 SSE,因为它允许我们以非阻塞的方式持续推送数据,而不会阻塞服务器的资源。

Spring WebFlux 是 Spring Boot 3 中用于构建响应式应用的核心框架,它可以无缝集成 SSE,为我们提供简单高效的服务器推送功能。

为什么选择响应式编程实现 SSE?

传统的阻塞式编程在处理长连接(如 SSE)时可能会占用大量服务器资源。响应式编程通过非阻塞 I/O 操作,不仅可以高效处理长时间的连接,还能在有新数据时立即推送给客户端。响应式流(如 Flux)天然适合于这种流式数据推送场景。

3. 实现 SSE 的基本步骤

我们将通过以下步骤实现一个简单的 SSE 服务端推送应用:

  1. 创建 Spring Boot 项目并引入 WebFlux 依赖。
  2. 实现服务端推送 SSE 事件流。
  3. 编写客户端接收 SSE 数据。
  4. 测试与优化。

3.1 创建 Spring Boot 项目

首先,创建一个新的 Spring Boot 3 项目,并确保引入了 spring-boot-starter-webflux 依赖。可以通过 Maven 或 Gradle 配置:

Maven 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

3.2 实现服务端推送 SSE 事件流

在 Spring WebFlux 中,SSE 通过返回 Flux<ServerSentEvent<T>> 这种响应流来实现。下面我们实现一个简单的 SSE 控制器,它会每隔一段时间向客户端推送当前的时间信息。

示例控制器

package com.coderjia.boot3webflux.controller;

import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.time.LocalTime;

/**
 * @author CoderJia
 * @create 2024/10/27 下午 07:03
 * @Description
 **/
@Controller
public class SseController {

    @GetMapping("/sse/stream")
    public Flux<ServerSentEvent<String>> streamSse() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> ServerSentEvent.<String>builder()
                        .id(String.valueOf(sequence))
                        .event("periodic-event")
                        .data("Current time: " + LocalTime.now())
                        .build());
    }
}

解释

  • Flux.interval(Duration.ofSeconds(1)):创建一个每秒发出事件的响应式流。
  • ServerSentEvent.builder():构建 ServerSentEvent 对象,它可以包含 id、event 和 data 等信息,符合 SSE 规范。
  • map():将流中的每个事件映射为 ServerSentEvent,并附带当前的时间信息。

3.3 客户端接收 SSE 数据

客户端可以使用 JavaScript 原生的 EventSource API 来接收服务器发送的 SSE 数据流。

示例 HTML + JavaScript 客户端

resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Example</title>
</head>
<body>
<h1>Server-Sent Events (SSE) Example</h1>
<div id="messages"></div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>

    const http = axios.create({
        baseURL: 'http://localhost:8080/',
        timeout: 100000,
        responseType: 'stream',
        onDownloadProgress: function (progressEvent) {
            // 获取 messages 元素
            const messagesElement = document.getElementById("messages");

            // 清除现有内容
            messagesElement.innerHTML = "";

            // 添加新内容
            const newElement = document.createElement("div");
            newElement.innerHTML = progressEvent.event.currentTarget.responseText + "<br/>";
            messagesElement.appendChild(newElement);
        },
    });

    http.get('/sse/stream')
        .then(function (response) {
            // 处理成功情况
            console.log(response);
        })
        .catch(function (error) {
            // 处理错误情况
            console.log(error);
        })
        .finally(function () {
            // 总是会执行
        });
</script>
</body>
</html>

解释

  • EventSource("/sse/stream"):EventSource 是浏览器提供的一个用于和服务器建立连接,接收服务器发送事件的接口。在客户端发起与服务器的 SSE 长连接。服务器通过 /sse/stream 推送事件。
  • onmessage:处理服务器发送的消息,并将消息显示在页面上。
  • onerror:当连接发生错误时关闭连接,避免持续消耗资源。

4. 测试 SSE

运行 Spring Boot 应用,并访问 /sse/stream,可以看到服务器每秒钟向客户端推送一次当前时间信息。

接口请求

header 里的 Content-Type 为 text/event-stream。

Content-Type

可以通过浏览器打开 http://localhost:8080/,在页面中将会每秒钟显示一次服务器推送的数据流。这就验证了 SSE 在 Spring Boot 3 中的实现。

浏览器展示

5. 优化与扩展

5.1 增加随机数据推送

为了模拟更真实的场景,可以增加一些随机数据或实时数据更新。假设我们希望推送随机的股票价格,我们可以这样修改:

@GetMapping("/sse/stocks")
public Flux<ServerSentEvent<String>> streamStockPrices() {
    return Flux.interval(Duration.ofSeconds(1))
            .map(sequence -> ServerSentEvent.<String>builder()
                    .id(String.valueOf(sequence))
                    .event("stock-update")
                    .data("Stock price: $" + ThreadLocalRandom.current().nextInt(100, 200))
                    .build());
}

在这个例子中,每秒推送一次随机的股票价格更新。

5.2 增加心跳检测(Ping)

SSE 连接如果长时间没有数据传输,可能会被中断。为此,SSE 规范推荐发送 “ping” 消息来保持连接活跃。可以通过 ServerSentEvent 的 comment() 来发送心跳信息:

@GetMapping("/sse/stream-with-ping")
public Flux<ServerSentEvent<String>> streamWithPing() {
    return Flux.interval(Duration.ofSeconds(1))
            .map(sequence -> {
                if (sequence % 5 == 0) {  // 每5秒发送一次心跳
                    return ServerSentEvent.<String>builder()
                            .comment("ping")
                            .build();
                } else {
                    return ServerSentEvent.<String>builder()
                            .data("Current time: " + LocalTime.now())
                            .build();
                }
            });
}

5.3 使用 MediaType.TEXT_EVENT_STREAM 响应

虽然 ServerSentEvent 是处理 SSE 的标准类,但你也可以直接返回 Flux<T>,Spring 会自动将其转换为事件流。如果你想简化代码,可以这样写:

@GetMapping(value = "/sse/simple", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> simpleSse() {
    return Flux.interval(Duration.ofSeconds(1))
            .map(sequence -> "Current time: " + LocalTime.now());
}

这里直接返回 Flux<String>,Spring WebFlux 会自动推送数据。

6. SSE 与 WebSocket 的对比

SSE 和 WebSocket 都是实时通信的重要技术,但它们有不同的适用场景:

  • SSE:单向通信,服务器推送数据到客户端,适合轻量级的通知、监控、消息更新等场景。使用简单,基于 HTTP。
  • WebSocket:双向通信,适合复杂的交互场景,如实时聊天、在线游戏等。WebSocket 是基于 TCP 的全双工连接,相对更复杂。

对于简单的实时更新场景,如股票价格更新、推送通知等,SSE 更加轻量且易于实现。

7. 总结

Spring Boot 3 提供了简单、强大的 SSE 实现,结合响应式编程的特性,使得我们可以轻松构建高效的服务器推送应用。在实际项目中,SSE 非常适合用于推送实时数据或监控信息,尤其在需要轻量且可靠的单向通信时。通过 Spring WebFlux 和 Project Reactor,SSE 的实现可以以非阻塞的方式运行,极大提升了应用的并发处理能力。

希望这篇博客对你理解 Spring Boot 3 中的 SSE 服务端推送有所帮助,如果有任何问题或想法,欢迎讨论!

SpringBoot SSE服务端主动推送事件详解 阅读详情

相关推荐

如何在Spring Boot中实现SSE(服务器发送事件)

SSE作为一种简单且有效的实时通信技术,为构建需要实时更新的Web应用提供了一个轻量级的解决方案。今天我们将探讨如何在Spring Boot应用中实现SSE(服务器发送事件),这是一种用于实现服务器向客户端推送实时数据的技术。它建立在HTTP协议之上,使用简单的文本格式进行通信,适合于需要实时更新的应用场景,比如实时股票报价、即时通讯等。:SSE基于标准的HTTP协议,无需复杂的依赖或插件,支持跨平台和跨浏览器使用。:与传统的轮询相比,SSE使用长连接技术,减少了服务器和客户端之间的通信开销。

微赚开发者技术分享博客 1751

springboot整合sse

SSE 在服务器和客户端之间打开一个单向通道,服务端响应的不再是一次性的数据包而是text/event-stream类型的数据流信息,在有数据变更时从服务器流式传输到客户端。整体的实现思路有点类似于在线视频播放,视频流会连续不断的推送到浏览器,你也可以理解成,客户端在完成一次用时很长(网络不畅)的下载。

qq_41604890的博客 8362

技能伤害继承英雄属性【War3地图编辑器】

风暴之锤跟随山丘之王的力量增长

ArYe 2303

Spring boot整合sse(使用详解)

SSE是一种基于HTTP长连接技术,允许服务器向客户端浏览器实时推送更新。客户端通过创建一个EventSource对象并指向服务器上的一个URL来发起请求,这个请求保持打开状态,服务器可以在这个单一的TCP连接上不断发送新的数据块。这些数据块被称为“事件”,每个事件包含类型(可选)、数据和一些元数据(如事件ID,重新连接时间间隔等)。服务器端以简单的文本格式(通常为UTF-8编码的纯文本)发送数据。

qq_67242480的博客 8672

C++动态规划详解

动态规划思想 一、动态规划概念: 动态规划(dp)是研究多步决策过程最优化问题的一种数学方法。在动态规划中,为了寻找一个问题的最优解(即最优决策过程),将整个问题划分成若干个相应的阶段,并在每个阶段都根据先前所作出的决策作出当前阶段最优决策,进而得出整个问题的最优解。即记住已知问题的答案,在已知的答案的基础上解决未知的问题。 在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后

weixin_51951103的博客 2万+

第七天 Labview进阶(7.4 NI Vision简单使用)

NIVision机器视觉软件使用指南 摘要:NIVision是National Instruments推出的高效机器视觉软件,具有硬件无缝集成、图形化编程和工业级部署等优势。本文介绍了NIVision的安装步骤(需Vision Acquisition和Vision Development模块)及三个典型应用案例:1)实物检测通过IMAQCreate等模块实现物体识别与坐标定位;2)OCR检测利用IMAQOCR系列模块完成字符识别;3)几何模板匹配使用IMAQLearnGeometricPattern等模块实

weixin_38637405的博客 771

SpringBoot集成SSE

例如可以在服务端将每次发送的事件ID值自动加 1,当浏览器接收到该事件ID后,下次与服务端建立连接后再请求的 Header 中将同时提交该事件ID,服务端检查该事件ID是否为上次发送的事件ID,如果与上次发送的事件ID不一致则说明浏览器存在与服务器连接失败的情况,本次需要同时发送前几次浏览器未接收到的数据。事件的唯一标识符,浏览器会跟踪事件ID,如果发生断连,浏览器会把收到的最后一个事件ID放到 HTTP Header。整数值,单位 ms,如果与服务器的连接丢失,浏览器将等待指定时间,然后尝试重新连接。

若鱼的专栏 8007

图形推理2-四大类六提示

图形推理笔记2

小y的学习笔记 6743

互联网架构系列全套SpringBoot2.x初级入门到实战

<p><img src="https://img-bss.csdnimg.cn/202102041031542766.png" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202102041032008465.png" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202102041032062681.png" alt="" /></p> <p><img src="https://img-bss.csdnimg.cn/202102041032114827.png" alt="" /></p>

VOS中历史话单显示通话会话超时中断详解

假设一种场景:  主叫拨打被叫,主叫方异常离线,被叫方接听,被叫方发送200ok至VOS,VOS传送200ok给主叫,但是主叫方未给出正常ack回应,VOS重发几次后(根据SIP参数设定的重发机制),然后VOS服务器会中断话务,历史话单终止原因为会话超时。 参考呼叫分析信令如下图: ...

非著名运维的博客 5017

Prism 入门02,区域介绍

什么是区域(Region)?区域,在Prism 框架中,区域是模块化的核心的功能之一,其主要作用是降低应用程序和模块之间的耦合度。使用方式:在应用程序的界面中,划分出某块区域,并为这个区域定义一个唯一的区域名称。那么通过这个区域名称,应用程序就可以找到指定的区域。并为这个区域动态放置一些容器或控件,从而呈现在界面中。

build2024 1126

Springboot 集成 SSE 向前端推送消息

Sse推送Sse介绍特点分析应用场景Spring Boot 集成测试 Sse介绍 sse(Server Sent Event),直译为服务器发送事件,顾名思义,也就是客户端可以获取到服务器发送的事件 我们常见的 http 交互方式是客户端发起请求,服务端响应,然后一次请求完毕;但是在 sse 的场景下,客户端发起请求,连接一直保持,服务端有数据就可以返回数据给客户端,这个返回可以是多次间隔的方式 特点分析 SSE 最大的特点,可以简单规划为两个 长连接 服务端可以向客户端推送信息 了解 websocke

Java老兵的后端进阶与AI前沿探索之路。 1万+

redhawk:STA timing data file解析

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧?STA timing data file分为以下几个部分:• Header• Name Map• Footer这部分报告设计的基本信息,例如文件类型,设计名称,分隔符等。...

m0_61544122的博客 1155

(十二)springboot实战——SSE服务推送事件案例实现

SSE(Server-Sent Events,服务器推送事件)是一种基于HTTP协议的服务器推送技术。它允许服务器向客户端发送异步的、无限长的数据流,而无需客户端不断地轮询或发起请求。这种技术可以用来实现实时通信、在线聊天、即时更新等功能。使用SSE时,客户端通过简单的HTTP请求与服务器建立连接,并在连接保持打开的情况下接收服务器发送的数据。服务器可以随时向客户端发送新的数据(以文本格式),并在数据前面添加特定的标识符,以便客户端能够正确地解析数据。

厉害哥哥的博客 6036

《UDS协议从入门到精通》系列——图解0x2E:通过ID写数据

图解数据包格式+直观的通信示例,迅速认识0x2E服务!!

车载系统攻城狮 3602

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

详解如何通过SSE实现Web站内消息推送

比Websocket简洁

WgRui的博客 4281

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

使用webflux处理大模型的SSE接口

基于 ‌Reactor 库‌(实现 Reactive Streams 规范),提供 Flux(0-N 元素流)和 Mono(0-1 元素流)处理异步数据流。采用 ‌Push 模式‌,数据就绪时自动触发处理,避免线程阻塞等待。

heouheou的博客 853

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Spring WebFlux 与 SSE 实现实时推送数据,精准推送到某个用户

通过 Spring WebFlux 和 SSE 的结合,我们可以轻松构建实时数据传输应用。SSE 提供了轻量级的服务器推送机制,而 Spring WebFlux 则为我们处理了底层的异步非阻塞 I/O 操作,并提供了简洁优雅的响应式编程模型,使得我们可以专注于业务逻辑的实现。相信随着实时数据需求的不断增长,Spring WebFlux + SSE 的组合将会在越来越多的项目中得到应用。

服务员的博客 4815

如何使用SSE结合WebFlux实现流式返回前端数据

最近deepseek非常火,公司也在不断的接入大模型;业务需求也再不断的接入API,当前需求就是如何实现流式返回前端数据,实现打字机似的返回前端;在网上搜索很多案例但是都不怎么实用,要么是get请求(但是改为post请求就不行),要么是示例代码不够清晰,根本无法无脑式实现,下面是我示例代码。遇到很多坑,网上也扒了半天,坑多的要命还有就是自己公司大模型的使用场景,本公司用平台创建应用,应用模型不同还会有很多坑,一定要用一个稳定的模型,否则数据输出会有问题;导包:SSE依赖包;

lxd1373006963的博客 1548
上一篇: 比较Spring AOP和AspectJ
下一篇: ChatGLM2-6B模型推理流程和模型架构详解
普通网友
博客等级 码龄4年 3126粉丝 192原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值