01 引言

之前专门介绍过流式响应的数据的接收、发送以及使用SSE由服务端推送数据的文章,但是要求前端必须使用EventSource订阅实现。

有没有通过直接通过浏览器访问或者Fetch API直接调用的方式呢?效果还能和ChatGPT一样,实现打字机的效果呢?

当然有。Spring框架在4.2及以后引入了强大额异步响应特性,其中ResponseBodyEmitterStreamingResponseBody是处理 HTTP 响应流式输出的两大核心利器,既不阻塞线程又不影响系统的相应能力。

我们一起了解一下吧!

02 StreamingResponseBody

全限定类名:

org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody

2.1 简介

StreamingResponseBody是一个函数式接口,适用于需要直接向 HttpServletResponse 的输出流写入原始字节数据的场景。它提供了一种低层次、高效的方式来流式传输数据。

StreamingResponseBody没有默认的实现,只有一个方法writeTo()。将文件或者数据直接写入输出流中,可以通过输出流的flush()方法,将数据刷出磁盘,减少内存的占用。

当我们需要将大量的数据或者文件响应给客户端时,由于处理耗时合作和内存的限制,我们就可以通过这种方式,逐步将数据响应给客户端,既可以提高用户体验又可以节省内存。

2.2 最佳实践

为了演示的方便,我们选择将文本内容逐步输出到浏览器端。

代码案例

间隔1s将数据包传给客户端:

@GetMapping(value = "/srb")
public StreamingResponseBody srb(HttpServletResponse response) {response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);StreamingResponseBody stream = os -> {for (int i = 0; i < 5; i++) {String data = "SRB 数据包【"+(i+1)+"】\n";os.write(data.getBytes());System.out.print(data);// 刷出磁盘os.flush();try {// 间隔1sThread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}};return stream;
}

因为没有默认的实现,这里使用了匿名内部类实现。

响应结果

03 ResponseBodyEmitter

全限定类名:

org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter

3.1 简介

ResponseBodyEmitter是一个类,官方还给出了具体的使用案例。该类使用异步线程发送数据,最终需要使用complete()结束数据的传输,否则就会一直等待的状态。

有没有发现我们之前介绍的SseEmitterResponseBodyEmitter有点类似,SseEmitter其实是ResponseBodyEmitter的子类。

SseEmitter作为特殊的ResponseBodyEmitter,专门支持Server-Sent Events的。

ResponseBodyEmitter 的抽象层次更高。它不仅可以发送字节,更重要的是可以发送对象,这些对象会被配置的 HttpMessageConverter 转换后发送(如转换为 JSON)。它允许你多次发送数据,非常适合服务器端事件(Server-Sent Events, SSE)或分块 JSON

3.2 最佳实践

代码案例

@GetMapping(value = "/rbe")
public ResponseBodyEmitter rbe(HttpServletResponse response) {response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);ResponseBodyEmitter emitter = new ResponseBodyEmitter(0L);CompletableFuture.runAsync(() -> {for (int i = 0; i < 5; i++) {String data = "RBE 数据包【"+(i+1)+"】\n";try {emitter.send(data);System.out.print(data);// 间隔1sThread.sleep(1000);} catch (Exception e) {throw new RuntimeException(e);}}emitter.complete();});return emitter;
}

响应结果

04 注意事项

两个类的案例中均有一行设置ContentType类型的代码:

response.setContentType(MediaType.TEXT_EVENT_STREAM_VALUE);

设置响应类型为text/event-stream,这一步很关键。否则直到全部的结果返回才会展示在浏览器端。

@GetMappingproduces属性并不能解决该问题,produces指定返回的内容类型,仅当request 请求头中的(Accept)类型中包含该指定类型才返回。

05 番外

聊到异步线程的响应,又想到了另外一个Spring MVC 专门处理异步请求的类DeferredResult,用法类似ResponseBodyEmitter,不同的是DeferredResult只能设置一次结果。

@GetMapping("/async")
public DeferredResult<String> async() {DeferredResult<String> deferredResult = new DeferredResult<>();CompletableFuture.runAsync(() -> {System.out.println("DeferredResult触发,等待结果");String data = "DeferredResult 数据包";try {// 间隔1sThread.sleep(2000);deferredResult.setResult(data);System.out.println("DeferredResult触发,完结");} catch (Exception e) {throw new RuntimeException(e);}});return deferredResult;
}

执行结果发现:他会等待deferredResult.setResult(data)发送数据之后才会结束响应。

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

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

相关文章

Git 删除文件

在 Git 中&#xff0c;删除文件同样被视为一种修改操作。下面我们通过实际操作演示如何删除文件。假设要删除文件 file5&#xff0c;如果你直接在文件系统中执行了删除&#xff1a;这种直接删除的方式并不会在 Git 中生效&#xff0c;反而会导致工作区与版本库不一致。使用 git…

虚幻基础:角色变换角色视角蒙太奇运动

能帮到你的话&#xff0c;就给个赞吧 &#x1f618; 文章目录角色视角机臂使用pawn控制旋转&#xff1a;旋转体将失去作用旋转体摄像机&#xff1a;可以使用旋转体控制&#xff1a;pawn不起作用角色变换角色移动&#xff1a;由移动组件控制移动方向&#xff1a;给组件任意一个方…

【LeetCode】31. 下一个排列

文章目录31. 下一个排列题目描述示例 1&#xff1a;示例 2&#xff1a;示例 3&#xff1a;提示&#xff1a;解题思路1. 问题本质与字典序回顾2. 经典算法三步曲&#xff08;必须原地、常数空间&#xff09;3. 直观示例与过程可视化4. 与“62. 不同路径”风格对应的分析维度4.1 …

CVPR2025丨VL2Lite:如何将巨型VLM的“知识”精炼后灌入轻量网络?这项蒸馏技术实现了任务专用的极致压缩

关注gongzhonghao【CVPR顶会精选】小模型&#xff08;Small Models&#xff09;通常指参数量较小、计算与存储成本更低的深度学习模型。近年来&#xff0c;它们在移动端部署、边缘计算和隐私保护等场景中快速发展&#xff0c;逐渐成为大模型的轻量化补充。随着蒸馏、剪枝、量化…

【SystemUI】锁屏来通知默认亮屏Wake模式

一、问题描述 基于 Android 14平台&#xff0c;锁屏状态下来通知时默认是进入Doze模式&#xff0c;此时屏幕不能点击只能查看通知信息且很快灭屏&#xff0c;用户体验不是很好&#xff0c;要求修改为通知直接亮屏。二、问题分析 梳理锁屏状态下&#xff08;特指设备息屏或处于D…

高并发写入、毫秒级查询——盘古信息携手 TDengine 时序数据库解决六大技术挑战

小T导读&#xff1a;广东盘古信息科技股份有限公司&#xff08;下文简称盘古信息&#xff09;成立于 2005 年&#xff0c;是一家基于工业互联网平台的数字化管理解决方案供应商&#xff0c;公司自主研发的 IMS&#xff08;数字化智能制造系统&#xff09;可为离散、流程及混合制…

Unity 打包 iOS,Xcode 构建并上传 App Store

一、准备工作&#xff08;环境、账号、证书与项目基础&#xff09;系统与工具macOS&#xff1a;使用与最新 Xcode 兼容的版本。Xcode&#xff1a;从 Mac App Store 安装最新稳定版&#xff08;建议与当前 App Store 必需的 Xcode 主版本保持一致&#xff09;。Unity&#xff1a…

Windows系统安装stata软件教程

1、解压缩2、点击next3、选择第一个&#xff0c;然后next4、这里随便填写就行5、选择stataMP&#xff0c;然后next6、这里改个路径&#xff0c;例如D:\Program Files\Stata18\7、这里不用管&#xff0c;选择next8、点击install&#xff0c;开始安装过程9、安装过程展示。10、最…

Android 开发 - 数据共享(数据共享、内容提供者实现、动态权限申请)

一、数据共享 1、内容提供者 内容提供者 ContentProvider 为 APP 存取内部数据提供统一的外部接口&#xff0c;让不同的应用之间得以共享数据2、流程理解 Client APP 将用户的输入内容通过 ContentProvider 跨进程通信传递给 Server APP3、数据访问 利用 ContentProvider 只实现…

【51单片机按键按下数码管秒增计时并LED亮释放停计时LED熄】2022-11-12

缘由单片机控制数码管及LED灯-嵌入式-CSDN问答 #include "REG52.h" sbit k1P3^0; unsigned char Js0;//计时 unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07 ,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0,64,15,56}; //共阴0~F消隐减号 void…

IBMS集成管理系统与3D数字孪生智能服务系统的应用

一九九二九九零七八八三一、数据全生命周期安全&#xff1a;从采集到销毁的闭环防护整合系统的核心风险之一是数据泄露或篡改&#xff08;如设备控制参数、建筑安防布局、人员动线数据&#xff09;&#xff0c;需覆盖数据流转的每个环节&#xff1a;1. 数据采集阶段&#xff1a…

Vue3组件加载顺序

父组件&#xff1a;QualityFile.vue<script setup lang"ts" name"QualityFile"> ...... </script><template><el-container class"container"><el-header class"header"><!-- 标题 --><div cl…

GitHub 宕机自救指南:应急预案与替代平台

GitHub 宕机自救指南:应急预案与替代平台 对于全球数百万开发者而言,GitHub 的稳定运行至关重要。然而,即便是最可靠的服务也可能出现意外中断。当 GitHub 无法访问时,代码托管、协作开发、持续集成与部署(CI/CD)等关键环节都将受到影响。本指南旨在为您提供一套完整的应…

将跨平台框架或游戏引擎开发的 macOS 应用上架 Mac App Store

随着 macOS 用户数量的增长&#xff0c;越来越多的开发者希望将自己的桌面应用或游戏上架到 Mac App Store&#xff0c;以便触达更多用户并获得官方的分发优势。但 Apple 的上架流程相比其他平台要严格得多&#xff0c;涉及签名、打包、沙盒、审核、公证等环节。本文将以博文的…

拷贝构造和赋值重载有什么区别

问题拷贝构造和赋值重载有什么区别我的回答拷贝构造函数和赋值运算符重载是C中两个看似相似但用途和行为有明显区别的特性。拷贝构造函数是用来创建一个新对象作为已存在对象的副本。它的形式是ClassName(const ClassName& other)&#xff0c;在以下情况会被调用&#xff1…

(笔记)输入法框架协作机制深度分析

概述 Android输入法框架&#xff08;IMF - Input Method Framework&#xff09;是Android系统中负责管理虚拟键盘和文本输入的核心组件。该框架协调输入法服务&#xff08;IME&#xff09;、应用程序和系统输入系统之间的复杂交互&#xff0c;为用户提供灵活高效的文本输入体验…

解开 Ansible 任务复用谜题:过滤器用法、Include/Import 本质差异与任务文件价值详解

1. 什么是变量过滤器&#xff08;Variable Filters&#xff09;&#xff1f;请列举几个常用的Jinja2过滤器及其用途。变量过滤器是在Jinja2模板中用于修改或格式化变量输出的工具。常用过滤器&#xff1a;to_json/to_yaml&#xff1a;将数据结构&#xff08;如字典、列表&#…

LangGraph-笑话评估器 应用实战

场景&#xff1a;用户指定冷笑话主题&#xff0c;生成冷笑话后&#xff0c;进行评估&#xff0c;如果不搞笑就需要重新生成以下代码实现了一个基于LangGraph的冷笑话自动生成与评估工作流。系统包含两个核心节点&#xff1a;生成器根据用户主题创作冷笑话&#xff0c;评估器对笑…

Paimon——官网阅读:Flink 引擎

Flink 引擎 快速入门 本文档是在Flink中使用Paimon的指南。 相关JAR包 Paimon目前支持Flink 1.20、1.19、1.18、1.17、1.16、1.15 。为获得更好的体验&#xff0c;我们推荐使用最新的Flink版本。 下载对应版本的JAR文件。 目前&#xff0c;Paimon提供两种类型的JAR包&…