Spring实现3种异步流式接口,解决接口超时烦恼

在现代Web开发中,接口超时是一个常见的问题,尤其是在处理耗时操作时。传统的同步接口在处理长时间任务时会阻塞请求线程,从而影响系统的响应能力。Spring框架提供了多种工具来支持异步流式接口,从而有效地解决这一问题。本文将详细讲解Spring中实现的三种异步流式接口方法:ResponseBodyEmitter、SseEmitter和StreamingResponseBody。

一、ResponseBodyEmitter

ResponseBodyEmitter适用于需要动态生成内容并逐步发送给客户端的场景,例如文件上传进度、实时日志等。使用ResponseBodyEmitter,可以在任务执行过程中逐步向客户端发送更新,使交互体验更加生动和自然。

使用示例:
java 复制代码
@GetMapping("/bodyEmitter")
public ResponseBodyEmitter handle() {
    // 创建一个ResponseBodyEmitter,-1代表不超时
    ResponseBodyEmitter emitter = new ResponseBodyEmitter(-1L);

    // 异步执行耗时操作
    CompletableFuture.runAsync(() -> {
        try {
            for (int i = 0; i < 10000; i++) {
                System.out.println("bodyEmitter " + i);
                // 发送数据
                emitter.send("bodyEmitter " + i + " @ " + new Date() + "\n");
                Thread.sleep(2000);
            }
            // 完成
            emitter.complete();
        } catch (Exception e) {
            // 发生异常时结束接口
            emitter.completeWithError(e);
        }
    });

    return emitter;
}

在这个示例中,通过模拟每2秒响应一次结果,可以看到页面数据在动态生成。ResponseBodyEmitter的超时时间可以设置为0或-1,表示连接不会超时。如果不设置,到达默认的超时时间后连接会自动断开。

二、SseEmitter

SseEmitter是ResponseBodyEmitter的一个子类,主要用于服务器向客户端推送实时数据,如实时消息推送、状态更新等场景。Server-Sent Events (SSE)技术在服务器和客户端之间打开一个单向通道,服务端响应的不再是一次性的数据包,而是text/event-stream类型的数据流信息。

使用示例:
java 复制代码
@GetMapping("/subSseEmitter/{userId}")
public SseEmitter sseEmitter(@PathVariable String userId) {
    log.info("sseEmitter: {}", userId);
    SseEmitter emitterTmp = new SseEmitter(-1L);
    // 将SseEmitter对象进行持久化,以便在消息产生时直接取出对应的发送器
    EMITTER_MAP.put(userId, emitterTmp);

    CompletableFuture.runAsync(() -> {
        try {
            // 模拟发送数据
            SseEmitter.SseEventBuilder event = SseEmitter.event()
                .data("sseEmitter" + userId + " @ " + LocalTime.now());
            emitterTmp.send(event);
            // 这里可以添加更多的发送逻辑
        } catch (Exception e) {
            emitterTmp.completeWithError(e);
        }
    });

    return emitterTmp;
}

在客户端,可以通过EventSource对象建立连接,并监听message事件来接收服务器发送的数据。

三、StreamingResponseBody

StreamingResponseBody用于将响应体作为流来输出,适用于需要输出大量数据且不适合使用ResponseBodyEmitter或SseEmitter的场景。

使用示例:
java 复制代码
@GetMapping("/streaming")
public StreamingResponseBody streaming() {
    return outputStream -> {
        // 异步执行耗时操作
        CompletableFuture.runAsync(() -> {
            try {
                for (int i = 0; i < 10000; i++) {
                    String data = "Streaming data " + i + "\n";
                    outputStream.write(data.getBytes());
                    outputStream.flush();
                    Thread.sleep(1000);
                }
                outputStream.close();
            } catch (Exception e) {
                // 处理异常
            }
        });
    };
}

在这个示例中,通过异步执行耗时操作,逐步将数据写入到响应的输出流中。StreamingResponseBody适用于需要持续输出数据流的场景,例如视频流、文件下载等。

总结

通过使用ResponseBodyEmitter、SseEmitter和StreamingResponseBody,Spring框架提供了强大的异步流式接口支持,有效地解决了接口超时的问题。这些方法允许在任务执行过程中逐步向客户端发送更新,提高了系统的响应能力和用户体验。根据具体的应用场景,可以选择合适的工具来实现异步流式接口。

相关推荐
程序猿DD4 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
蛋蛋的就会顺顺的6 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i7 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8267 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡7 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林8 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne9 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF9 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_9 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li10 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉