Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE)流式 JSON 内容 ,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会导致数据必须等待全部接收完毕后再处理,违背了流式传输的初衷。

本文将介绍如何在 Spring Boot 2.7.x 中使用 RestTemplate 实现一个流式响应的中转接口。

一、关键点说明

  1. 禁用请求缓冲:

    通过 SimpleClientHttpRequestFactory#setBufferRequestBody(false) 禁用缓冲,确保流式传输生效。

  2. 设置响应为 SSE 格式:

    设置 HttpServletResponse 的响应头为 text/event-stream,支持前端基于 EventSource 的实时响应。

  3. 使用 RestTemplate.execute 方法:

    通过 RestTemplate.execute() 方法自定义 RequestCallbackResponseExtractor 实现对输入输出流的精细控制。

二、完整代码实现

复制代码
/**
 * 处理流式响应的HTTP请求方法(流式响应, Spring Boot 2.7.x 兼容)
 *
 * @param requestBody 请求体内容
 * @param url         请求URL
 * @param httpMethod  请求方法
 * @param response    HttpServletResponse,用于直接返回流数据
 */
public static void executeStreamingRequest(
        Map<String, Object> requestBody,
        String url,
        HttpMethod httpMethod,
        HttpServletResponse response) throws IOException {

    // 1. 配置RestTemplate(启用流式)
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false); // 关键:禁用请求缓冲
    requestFactory.setConnectTimeout(30000);
    requestFactory.setReadTimeout(60000);

    RestTemplate restTemplate = new RestTemplate(requestFactory);

    // 2. 设置请求头
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);

    // 3. 执行流式请求
    try {
        log.info("【开始流式请求】URL: {}", url);
        restTemplate.execute(
                URI.create(url),
                httpMethod,
                new RequestCallback() {
                    @Override
                    public void doWithRequest(ClientHttpRequest request) throws IOException {
                        request.getHeaders().putAll(headers);
                        if (requestBody != null) {
                            new ObjectMapper().writeValue(request.getBody(), requestBody);
                        }
                    }
                },
                new ResponseExtractor<Void>() {
                    @Override
                    public Void extractData(ClientHttpResponse clientResponse) throws IOException {
                        // 设置响应头
                        response.setContentType("text/event-stream");
                        response.setCharacterEncoding("UTF-8");

                        // 流式传输
                        try (InputStream is = clientResponse.getBody();
                             OutputStream os = response.getOutputStream()) {
                            byte[] buffer = new byte[8192];
                            int bytesRead;
                            while ((bytesRead = is.read(buffer)) != -1) {
                                os.write(buffer, 0, bytesRead);
                                os.flush(); // 立即刷新
                            }
                        }
                        return null;
                    }
                }
        );
    } catch (RestClientException e) {
        log.error("流式请求失败", e);
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.getWriter().write("服务调用失败: " + e.getMessage());
    }
}

三、使用场景举例

  • 转发 OpenAI 的流式 API 响应

  • 转发后端 AI 推理接口的逐步响应

  • 转发日志、进度等后台任务推送数据

四、注意事项

  • 保证上下游接口支持长连接和流式传输

  • 防止浏览器缓冲影响效果,前端建议使用 EventSourcefetch + reader 模式消费

  • 若上游响应为分块传输(chunked),务必确保 header 中包含 Transfer-Encoding: chunked

一线网资源-全网一站式平台

相关推荐
收破烂的小熊猫~7 分钟前
《Java修仙传:从凡胎到码帝》第四章:设计模式破万法
java·开发语言·设计模式
小七mod12 分钟前
【MyBatis】MyBatis与Spring和Spring Boot整合原理
spring boot·spring·mybatis
猴哥源码15 分钟前
基于Java+SpringBoot的动物领养平台
java·spring boot
老任与码19 分钟前
Spring AI Alibaba(1)——基本使用
java·人工智能·后端·springaialibaba
小兵张健20 分钟前
武汉拿下 23k offer 经历
java·面试·ai编程
FreeBuf_30 分钟前
Apache组件遭大规模攻击:Tomcat与Camel高危RCE漏洞引发数千次利用尝试
java·tomcat·apache
无妄-202441 分钟前
软件架构升级中的“隐形地雷”:版本选型与依赖链风险
java·服务器·网络·经验分享
qqxhb1 小时前
零基础数据结构与算法——第四章:基础算法-排序(上)
java·数据结构·算法·冒泡·插入·选择
华子w9089258591 小时前
基于 SpringBoot+VueJS 的农产品研究报告管理系统设计与实现
vue.js·spring boot·后端
猴哥源码1 小时前
基于Java+SpringBoot的在线小说阅读平台
java·spring boot