news 2026/4/17 17:37:43

SpringBoot + ResponseBodyEmitter 实时异步流式推送

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot + ResponseBodyEmitter 实时异步流式推送

目前市面上异步推送大多用的是websocket或者http轮训,今天咱们换一种更为简便的方式来实现流式输出,那就是ResponseBodyEmitter

其实,ResponseBodyEmitter并非新技术,早在 Spring Framework 4.2 版本就已被引入。直到最近,我们在开发一个滚动日志输出功能时,才深入了解到它的强大之处。

ResponseBodyEmitter 的作用

相较于 websocket 技术,ResponseBodyEmitter更加简单易用。它主要用于处理异步的 HTTP 响应,其核心优势在于允许逐步将数据发送到客户端,而非一次性发送所有内容。这一特性使得它在需要长时间处理或进行流式传输的场景中表现出色。需要注意的是,ResponseBodyEmitter本质上是一个接口。

使用场景

  1. 长轮询:服务器在有数据时会立即响应客户端请求,若暂无数据,则保持连接开放,等待数据到来。
  2. 服务器推送事件 (SSE):服务器能够持续不断地向客户端推送各类事件,实现实时交互。
  3. 流式传输:可逐步发送大量数据,像文件下载或者实时数据流传输等场景都适用。
  4. 异步处理:在处理耗时任务时,能逐步返回处理结果,避免客户端长时间等待,提升用户体验。

业务场景举例

在实际业务中,ResponseBodyEmitter有着广泛的应用,比如进度条的实时更新、实时聊天功能、股票价格的实时更新、系统日志的流式输出以及 AI 的流式响应等。

实时日志流实战

接下来,我们通过一个简单的实时日志流功能,来深入了解ResponseBodyEmitter的使用。假设我们有一个应用程序,需要实时查看服务器的日志,以便快速定位和解决问题。

创建控制器

首先,我们在 Spring Boot 应用中创建一个控制器,借助ResponseBodyEmitter实现实时日志流。

import org.springframework.http.MediaType; 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.ResponseBodyEmitter; @RestController @RequestMapping("/api/log") publicclass LogController { @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public ResponseBodyEmitter streamLogs() { ResponseBodyEmitter emitter = new ResponseBodyEmitter(); // 开启异步线程处理数据并发送 new Thread(() -> { try { while (true) { String logEntry = getLatestLogEntry(); if (logEntry != null) { emitter.send(logEntry); } // 每秒检查一次日志更新 Thread.sleep(1000); } } catch (Exception e) { // 出现异常时结束响应并传递错误信息 emitter.completeWithError(e); } }).start(); return emitter; } private String getLatestLogEntry() { // 模拟从日志文件中获取最新日志条目 return"2025-02-12 12:00:00 - INFO: User logged in successfully."; } }

运行效果

当我们启动这个应用程序,并访问/api/log/stream路径时,就能看到一个实时更新的日志流。服务器会每秒向客户端推送一条新的日志条目,客户端会将其显示在页面上,效果如下:

ResponseBodyEmitter 的核心方法

  • send(Object data):向客户端发送数据,该方法可以多次调用,实现数据的逐步发送。
  • complete():用于结束响应流,表示数据已经全部发送完毕。
  • onTimeout(Runnable callback):设置超时回调函数,当连接超时时,会执行该回调。
  • onCompletion(Runnable callback):设置完成回调函数,当数据发送完成后,会执行该回调。

ResponseBodyEmitter 工作原理

异步数据生成与推送

在传统的 HTTP 请求 - 响应模式中,服务器通常需要等待整个响应数据生成完成后,才会将其一次性发送给客户端。而ResponseBodyEmitter打破了这种模式,它允许服务端在任务执行过程中异步地生成响应数据。

当有部分数据准备好时,就可以立即调用send()方法将这些数据推送给客户端,而无需等待整个任务完成。这就好比一场接力赛,每完成一段赛程(生成一部分数据),就马上将接力棒(数据)传递给客户端,大大提高了数据传输的实时性。

分块传输机制

ResponseBodyEmitter采用了 HTTP 的分块编码(Chunked Encoding)方式来传输数据。在传统的 HTTP 响应中,通常需要在响应头中明确指定Content-Length,表示整个响应数据的长度。但在分块传输中,服务器不会提前设置Content-Length,而是将数据分成多个独立的块,每个块都有自己的长度标识。

客户端在接收到数据块后,可以立即对其进行处理,而不必等待整个响应数据接收完毕。这种方式使得数据可以边生成边传输,减少了客户端的等待时间,提高了用户体验。

连接生命周期管理

为了确保资源的合理使用,ResponseBodyEmitter提供了对连接生命周期的有效管理。当所有数据都发送完毕后,需要调用complete()方法来明确告知客户端响应结束,关闭连接。如果在数据传输过程中出现异常,可以调用completeWithError()方法,结束响应并向客户端传递错误信息。

这样可以避免连接长时间保持开放,造成资源浪费。

注意事项

  1. 客户端支持:虽然大多数浏览器和 HTTP 客户端库都支持分块传输,但某些老旧的客户端可能存在兼容性问题。
  2. 超时设置:为避免长连接长时间占用资源,可以为ResponseBodyEmitter设置超时时间,示例代码如下:
emitter.onTimeout(() -> emitter.complete());
  1. 线程安全ResponseBodyEmittersend()方法是线程安全的,但在使用时需要注意控制任务线程的生命周期,避免出现资源泄漏。
  2. 连接关闭:务必确保在任务结束时调用complete()completeWithError()方法,否则可能导致连接无法正常关闭,造成资源浪费。

小结

ResponseBodyEmitter是 Spring 框架提供的轻量级流式传输解决方案,它能够显著提升高并发和实时性场景下的用户体验。通过ResponseBodyEmitter,我们可以轻松实现服务器向客户端的实时数据推送。

无论是进度条的实时更新、实时聊天、股票价格的实时监控还是系统日志的流式输出,ResponseBodyEmitter都能帮助我们构建更加动态和互动的应用程序。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/8 5:49:21

基于Spring Boot的网络安全意识教育平台的设计与实现

目录 摘要内容关键技术创新点 开发技术路线结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 摘要内容 基于Spring Boot的网络安全意识教育平台的设计与实现旨在通过现代化技术手段提升用户的网络安全意识,帮助用户识别和防…

作者头像 李华
网站建设 2026/4/13 9:17:43

python老年人膳食营养服务网站 养生食谱推荐系统

目录 老年人膳食营养服务网站摘要养生食谱推荐系统摘要技术实现要点社会价值体现 开发技术路线结论源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 老年人膳食营养服务网站摘要 该网站旨在为老年人提供科学、个性化的膳食营养服务&#…

作者头像 李华
网站建设 2026/4/15 8:00:35

完整演示 Git Flow 所有分支的创建与流转过程的 实操命令示例

✅ 假设项目刚初始化,只有 main 分支 ✅ 所有操作基于命令行 ✅ 模拟一个完整周期:开发 → 发布 → 热修复🚀 第 0 步:初始化项目(仅有 main) # 创建项目目录 mkdir my-project && cd my-project# …

作者头像 李华
网站建设 2026/4/10 20:25:35

适老化移动应用界面易用性测试体系构建与实施策略

一、适老化测试的时代背景与核心挑战 人口结构变革的紧迫需求 我国60岁以上人口占比已达18.7%(2.64亿),老年群体数字需求激增与界面使用障碍的矛盾日益凸显。测试人员需直面三大核心挑战:视觉感知衰退导致的界面元素识别困难&…

作者头像 李华