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/16 17:48:56

2026年毕业论文维普AIGC检测率高于30%怎么办?避坑指南

答辩前7天,导师说我的论文AIGC率42%不能送审 距离答辩还有7天的时候,导师把我叫到办公室。他把电脑屏幕转过来给我看,维普AIGC检测报告上赫然显示42.6%。"学校今年的红线是30%,你这个过不了。"他说这句话的时候表情很平…

作者头像 李华
网站建设 2026/4/15 7:21:12

2026年DeepSeek写的论文维普AIGC查重率98%怎么办

2026年DeepSeek写的论文维普AIGC查重率98%怎么办 上个月帮一个学弟看论文,他打开维普检测结果的时候我俩都沉默了:AIGC疑似比例98%。 98%什么概念?基本上维普认为你整篇论文都是AI写的。而他确实是用DeepSeek写的。事情的经过是这样的&…

作者头像 李华
网站建设 2026/4/16 9:25:38

HTML 用户二次确认:提升操作安全性的关键实践

在 Web 开发中,用户交互的安全性始终是首要考虑因素。特别是对于敏感操作(如删除数据、修改密码、支付确认等),简单的点击即执行模式存在巨大风险。本文将深入探讨如何通过 HTML 和 JavaScript 实现用户二次确认机制,帮…

作者头像 李华
网站建设 2026/4/5 6:57:15

RK3588 分区表详解:每一块分区到底装了什么、负责什么

📺 B站:博主个人介绍 📘 博主书籍-京东购买链接*:Yocto项目实战教程 📘 加博主微信,进技术交流群: jerrydev RK3588 分区表详解:每一块分区到底装了什么、负责什么 目标&#xff1…

作者头像 李华
网站建设 2026/4/15 18:53:59

闭眼入!8个AI论文工具测评:专科生毕业论文+开题报告全攻略

在当前学术研究日益数字化的背景下,AI写作工具已成为提升效率、优化内容质量的重要助手。然而面对市场上五花八门的产品,如何选择真正适合自己的工具成为难题。为此,笔者基于2026年的实测数据与真实用户反馈,围绕功能覆盖、核心服…

作者头像 李华