09. Springboot集成sse服务端推流

目录

1、前言

2、什么是SSE

2.1、技术原理

2.2、SSE和WebSocket

2.2.1、SSE (Server-Sent Events)

2.2.2、WebSocket

2.2.3、选择 SSE 还是 WebSocket?

3、Springboot快速集成

3.1、添加依赖

3.2、创建SSE控制器

3.2.1、SSEmitter创建实例

3.2.2、SSEmitter API

3.2.3、SSEmitter注册回调

4、小结


1、前言

如果项目中有一个场景,假设对接ChatGPT或对接天气类接口的时候,需要服务端主动往客户端进行消息推送或推流。通常的做法有:

  • 客户端提供接收数据接口,服务端开启定时轮询,定时向客户端发起http请求
  • 客户端提供定时轮询服务,定时向服务端发起http请求接口
  • 使用websocket实时通讯

那么今天再介绍另一种机制:SSE,也就是服务器发送事件机制。

2、什么是SSE

SSE(Server-Sent Events)是一种允许服务器向客户端推送实时数据的技术,它建立在 HTTP 和简单文本格式之上,提供了一种轻量级的服务器推送方式,通常也被称为“事件流”(Event Stream)。他通过在客户端和服务端之间建立一个长连接,并通过这条连接实现服务端和客户端的消息实时推送。

2.1、技术原理

SSE是建立在HTTP协议之上的,所以原理比较简单,也与HTTP原理类似:

1)建立连接:

客户端通过普通的 HTTP 请求向服务器发起连接请求,类似于普通的 Web 请求。这个请求的关键在于使用了 text/event-stream 的 MIME 类型,告知服务器该请求是 SSE 请求。

httpCopy codeGET /sse/stream HTTP/1.1
Host: example.com
Accept: text/event-stream

2)服务器处理请求:

服务器接收到 SSE 请求后,会在连接上保持打开状态,不会立即关闭。这是与普通的请求-响应模式的主要不同之处。服务器端通过这个持久连接向客户端发送数据。

3)数据推送:

服务器端通过打开的连接,周期性地向客户端发送消息。这些消息以文本的形式发送,并遵循一定的格式,通常以 data 字段表示消息内容。

httpCopy codeHTTP/1.1 200 OK
Content-Type: text/event-streamdata: This is a message\n\n

上述例子中,data 字段包含了实际的消息内容,两个换行符(\n\n)表示消息的结束。

4)客户端接收消息:

客户端通过监听连接的 message 事件来接收服务器推送的消息。一旦接收到消息,客户端可以采取相应的操作,例如更新界面内容。

javascriptCopy codeconst eventSource = new EventSource('/sse/stream');eventSource.onmessage = function (event) {console.log('Received message:', event.data);// 处理消息,例如更新界面
};

5)连接关闭:

当服务器端不再需要向客户端推送消息时,或者发生错误时,服务器可以关闭连接。客户端也可以通过调用 eventSource.close() 来关闭连接。

2.2、SSE和WebSocket

提到SSE,那自然要提一下WebSocket了。WebSocket是一种HTML5提供的全双工通信协议(指可以在同一时间内允许两个设备之间进行双向发送和接收数据的通信协议),基于TCP协议,并复用HTTP的握手通道(允许一次TCP连接中传输多个HTTP请求和相应),常用于浏览器与服务器之间的实时通信。

SSE和WebSocket尽管功能类似,都是用来实现服务器向客户端实时推送数据的技术,但还是有一定区别:

2.2.1、SSE (Server-Sent Events)

  1. 简单性:SSE 使用简单的 HTTP 协议,通常建立在标准的 HTTP 或 HTTPS 连接之上。这使得它对于一些简单的实时通知场景非常适用,特别是对于服务器向客户端单向推送数据。
  2. 兼容性:SSE 在浏览器端具有较好的兼容性,因为它是基于标准的 HTTP 协议的。即使在一些不支持 WebSocket 的环境中,SSE 仍然可以被支持。
  3. 适用范围:SSE 适用于服务器向客户端单向推送通知,例如实时更新、事件通知等。但它仅支持从服务器到客户端的单向通信,客户端无法直接向服务器发送消息。

2.2.2、WebSocket

  1. 全双工通信: WebSocket 提供了全双工通信,允许客户端和服务器之间进行双向实时通信。这使得它适用于一些需要双向数据交换的应用,比如在线聊天、实时协作等。
  2. 低延迟:WebSocket 的通信开销相对较小,因为它使用单一的持久连接,而不像 SSE 需要不断地创建新的连接。这可以降低通信的延迟。
  3. 适用范围: WebSocket 适用于需要实时双向通信的应用,特别是对于那些需要低延迟、高频率消息交换的场景。

2.2.3、选择 SSE 还是 WebSocket?

  • 简单通知场景:如果你只需要服务器向客户端推送简单的通知、事件更新等,而不需要客户端与服务器进行双向通信,那么 SSE 是一个简单而有效的选择。
  • 双向通信场景:如果你的应用需要实现实时双向通信,例如在线聊天、协作编辑等,那么 WebSocket 是更合适的选择。
  • 兼容性考虑: 如果你的应用可能在一些不支持 WebSocket 的环境中运行,或者需要考虑到更广泛的浏览器兼容性,那么 SSE 可能是一个更可行的选择。

3、Springboot快速集成

3.1、添加依赖

Springboot项目中,sse不需要额外添加依赖,引用了web相关的springboot依赖即可:

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

3.2、创建SSE控制器

这里简单创建一个控制器类,用于处理SSE请求。在JAVA中通常使用SSEmitter来实现sse的消息推送。

package com.example.springbootsse.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.Date;@RestController
@RequestMapping("/sse")
public class SSEmitterController {@GetMapping("/stream")public SseEmitter stream() {// 用于创建一个 SSE 连接对象SseEmitter emitter = new SseEmitter();// 在后台线程中模拟实时数据new Thread(() -> {try {for (int i = 0; i < 10; i++) {// emitter.send() 方法向客户端发送消息// 使用SseEmitter.event()创建一个事件对象,设置事件名称和数据emitter.send(SseEmitter.event().name("message").data("[" + new Date() + "] Data #" + i));Thread.sleep(1000);}// 数据发送完成后,关闭连接emitter.complete(); } catch (IOException | InterruptedException e) {// 发生错误时,关闭连接并报错emitter.completeWithError(e);}}).start();return emitter;}
}

查看执行结果,可以看到每一秒服务端都会自动像客户端推送messag消息:

我们来关注下SSEmitter这个类,SseEmitter 是 Spring Framework 中用于实现 Server-Sent Events(SSE)的一个类。它允许服务器向客户端推送数据,通过建立一个持久连接,实现服务器向客户端的实时单向通信。在 Spring 框架中,SseEmitter 类通常用于处理 SSE 请求,推送事件给客户端。

3.2.1、SSEmitter创建实例

SSEmitter提供了两个构造函数用于创建实例。在创建实例时,我们可以指定超时时间timeout,如果传0或使用无参构造,则表示永不过期。连接超时是指在一段时间内没有数据传输时,连接将被认为是超时的,并自动关闭。

3.2.2、SSEmitter API

除此以外,SSEmitter还提供了几种API,如上面例子中使用到的:

  1. emitter.send() 方法向客户端发送消息。
  2. SseEmitter.event() 创建一个事件对象,设置事件名称和数据。
  3. emitter.complete() 表示数据发送完成后关闭连接。
  4. emitter.completeWithError(e) 在发生错误时关闭连接并报错。

3.2.3、SSEmitter注册回调

SseEmitter 可以通过注册回调函数来处理服务器端发往客户端的事件。当服务器端有新的数据需要推送给客户端时,注册的回调函数将会被调用。SSEmitter继承了ResponseBodyEmitter,提供的一系列注册回调函数有:

示例代码:

package com.example.springbootsse.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.Date;@RestController
@RequestMapping("/sse")
public class SSEmitterController {@GetMapping("/stream")public SseEmitter stream() {// 3S超时SseEmitter emitter = new SseEmitter(10000L);// 注册回调函数,处理服务器向客户端推送的消息emitter.onCompletion(() -> {System.out.println("Connection completed");// 在连接完成时执行一些清理工作});emitter.onTimeout(() -> {System.out.println("Connection timeout");// 在连接超时时执行一些处理emitter.complete();});// 在后台线程中模拟实时数据new Thread(() -> {try {for (int i = 0; i < 10; i++) {emitter.send(SseEmitter.event().name("message").data("[" + new Date() + "] Data #" + i));Thread.sleep(1000);}emitter.complete(); // 数据发送完成后,关闭连接} catch (IOException | InterruptedException e) {emitter.completeWithError(e); // 发生错误时,关闭连接并报错}}).start();return emitter;}
}
  1. onCompletion():在连接完成时候触发,可在连接完成时执行一些清理工作
  2. onTimeout():当连接超时时触发
  3. onError():当连接异常时触发
  4. completeWithError(e):用于发生错误时,关闭连接并报错

4、小结

其实SSE已经出来很久了,但是熟知他的人却很少,大多数项目中还是直接使用了websocket技术。直到最近ChatGPT火了之后,很多项目需要对接GPT进行实时推流,才逐渐又被人提起。所以借此篇文章给自己扫盲一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/246423.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++:引用

目录 概念&#xff1a; 引用的使用格式&#xff1a; 引用特性&#xff1a; 常引用 使用场景&#xff1a; 1、做参数 二级指针时的取别名 一级指针取别名 一般函数取别名 2、做返回值 函数返回值的原理&#xff1a; 引用的返回值使用&#xff1a; 引用和指针的对比&…

YOLOv8训练自己的数据集,通过LabelImg

记录下labelImg标注数据到YOLOv8训练的过程,其中容易遇到labelImg的坑 数据集处理 首先在mydata下创建4个文件夹 images文件夹下存放着所有的图片&#xff0c;包括训练集和测试集等。后续会根据代码进行划分。 json文件夹里存放的是labelImg标注的所有数据。需要注意的是&…

Ubuntu findfont: Font family ‘SimHei‘ not found.

matplotlib中文乱码显示 当我们遇到这样奇怪的问题时, 结果往往很搞笑 尝试1不行 Stopping Jupyter Installing font-manager: sudo apt install font-manager Cleaning the matplotlib cache directory: rm ~/.cache/matplotlib -fr Restarting Jupyter. 尝试2 This work fo…

Spring Boot 中的外部化配置

Spring Boot 中的外部化配置 一、配置文件基础1.配置文件格式&#xff08;1&#xff09;YAML 基本语法规则&#xff08;2&#xff09;YAML 支持三种数据结构 2.application 文件3.application.properties 配置文件4.application.yml 配置文件5.Environment6.组织多文件7.多环境…

HTTP动态代理的原理及其对网络性能的影响

HTTP动态代理是一种通过代理服务器来转发HTTP请求和响应数据的网络技术&#xff0c;它可以优化网络性能、提高网络安全性&#xff0c;并解决跨域请求的问题。本文将详细介绍HTTP动态代理的原理及其对网络性能的影响。 一、HTTP动态代理的原理 HTTP动态代理的基本原理是在客户…

微信小程序(十四)分包和分包预加载

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.分包的配置 2.分包预加载的写法 先说说为什么需要分包&#xff1a; 小程序追求小而快&#xff0c;主包的大小控制是小程序上线的硬性要求&#xff0c;分包有利于小程序优化加载速度 分包的注意事项&#xff1a…

大模型+自动驾驶

论文&#xff1a;https://arxiv.org/pdf/2401.08045.pdf 大型基础模型的兴起&#xff0c;它们基于广泛的数据集进行训练&#xff0c;正在彻底改变人工智能领域的面貌。例如SAM、DALL-E2和GPT-4这样的模型通过提取复杂的模式&#xff0c;并在不同任务中有效地执行&#xff0c;从…

数字图像处理(实践篇)三十一 Raw图像数据转为RGB图像实践

目录 1 Raw图像和RGB图像 2 Raw图像的排布方式 3 方案 4 实践 5 其他 1 Raw图像和RGB图像 Raw图片是未经压缩的,没有任何数据损失,Raw图片保留了从图像传感器捕获的每个像素的原始信息,因此可以实现更高的图像质量。

用C语言实现贪吃蛇游戏!!!(破万字)

前言 大家好呀&#xff0c;我是Humble&#xff0c;不知不觉在CSND分享自己学过的C语言知识已经有三个多月了&#xff0c;从开始的C语言常见语法概念说到C语言的数据结构今天用C语言实现贪吃蛇已经有30余篇博客的内容&#xff0c;也希望这些内容可以帮助到各位正在阅读的小伙伴…

Flink实现数据写入MySQL

先准备一个文件里面数据有&#xff1a; a, 1547718199, 1000000 b, 1547718200, 1000000 c, 1547718201, 1000000 d, 1547718202, 1000000 e, 1547718203, 1000000 f, 1547718204, 1000000 g, 1547718205, 1000000 h, 1547718210, 1000000 i, 1547718210, 1000000 j, 154771821…

基于51单片机智能电子秤

实物显示效果&#xff1a; https://www.bilibili.com/video/BV1Wb4y1A7Aw/?vd_source6ff7cd03af95cd504b60511ef9373a1d 功能介绍&#xff1a; &#xff08;1&#xff09;用键盘设计单价&#xff1b; &#xff08;2&#xff09;称重后同时显示该物品的重量、单价和总额&…

记签名机制

签名过程&#xff1a; 首先将数据源通过摘要算法获取到数字摘要 对数字摘要用私钥进行加密得到签名 将原始消息 以及签名发送给消息接收方 接收方用公钥解密得到数字摘要 用同样的摘要算法将原始消息进行计算 比较得到的数字摘要与解密后的是否一致 Android学习笔记——Androi…

【精选推荐】3款强大的API渗透测试工具

1免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测。 2前言 给大家介绍三款优秀的…

智能GPT图书管理系统(SpringBoot2+Vue2)、接入GPT接口,支持AI智能图书馆

☀️技术栈介绍 ☃️前端主要技术栈 技术作用版本Vue提供前端交互2.6.14Vue-Router路由式编程导航3.5.1Element-UI模块组件库&#xff0c;绘制界面2.4.5Axios发送ajax请求给后端请求数据1.2.1core-js兼容性更强&#xff0c;浏览器适配3.8.3swiper轮播图插件&#xff08;快速实…

VR拍摄+制作

1.VR制作需要的图片宽高是2:1&#xff0c;需要360✖️180的图片&#xff0c;拍摄设备主要有两种&#xff1a; 1&#xff09;通过鱼眼相机拍摄&#xff0c;拍摄一组图片&#xff0c;然后通过PTGui来合成(拍摄复杂) 2&#xff09;全景相机&#xff0c;一键拍摄直接就能合成需要的…

C# Graphics对象学习

Graphics对象用于进行绘制&#xff1b; 从哪个对象获取的Graphics&#xff0c;然后进行绘制&#xff0c;就绘制到该对象上&#xff1b; 从位图获取Graphics&#xff0c;然后进行绘制&#xff0c;绘制到该位图上&#xff1b; 从某个控件获取Graphics&#xff0c;然后绘制&…

智慧文旅:提升旅游体验与推动经济发展的新动力

一、智慧文旅的定义与意义 智慧文旅&#xff0c;即智慧文化旅游&#xff0c;是一种以当地特色文化元素为核心驱动&#xff0c;利用现代科技手段实现旅游景区全面智慧升级的旅游模式。其意义在于为游客提供高效便捷的旅游信息化服务&#xff0c;提升旅游体验&#xff0c;同时推…

蓝桥杯备战——6.串口通讯

1.分析原理图 由上图我们可以看到串口1通过CH340接到了USB口上&#xff0c;通过串口1我们就能跟电脑进行数据交互。 另外需要注意的是STC15F是有两组高速串口的&#xff0c;而且可以切换端口。 2.配置串口 由于比赛时间紧&#xff0c;我们最好不要去现场查寄存器手册&#x…

Unity应用在车机上启动有概率黑屏的解决方案

问题描述 最近将游戏适配到车机上&#xff08;Android系统&#xff09;&#xff0c;碰到了一个严重bug&#xff0c;启动的时候有概率会遇到黑屏&#xff0c;表现就是全黑&#xff0c;无法进入Unity的场景。 经过查看LogCat日志&#xff0c;也没有任何报错&#xff0c;也没有任…

Python网络爬虫分步走之 – 第一步:什么是网络爬虫?

Python网络爬虫分步走之第一步&#xff1a;什么是网络爬虫&#xff1f; Web Scraping in Python Step by Step – 1st Step, What is Web Crawler? By JacksonML 1. 什么是网络爬虫&#xff1f; 在能够使用Google搜索引擎的场合&#xff0c;你是否尝试过简单搜索&#xff…