You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring模拟分块返回端点:如何让浏览器实时接收分块内容?

问题描述

我们团队遇到一个问题:某个GET端点在特定参数下会分块返回超大JSON,例如1000行的JSON会分批返回,导致应用因超时无法完整获取数据。为调试该问题,我们需要模拟该端点的行为。目前已实现一个模拟端点,生成随机字符串并分块写入OutputStream后刷新,但浏览器和POSTMAN均在所有内容返回后才显示,而非实时接收分块。请问如何修改才能实现实时分块显示?

当前实现代码
private static final int readBufSize = 10;
  
private static final int generatedStringSize = readBufSize * 10000;

@GetMapping(path = "/v2/payload/mocklargepayload")
public void simulateLargePayload(HttpServletResponse response){
  try(InputStream inputStream = IOUtils.toInputStream(RandomStringUtils.randomAlphanumeric(generatedStringSize));
      OutputStream outputStream = response.getOutputStream()) {
    final byte[] buffer = new byte[readBufSize];
    for(int i = 0; i < generatedStringSize; i+= readBufSize){
      inputStream.read(buffer, 0, readBufSize - 1);
      buffer[buffer.length - 1] = '\n';
      log.info("Read bytes: {}", buffer);
      outputStream.write(buffer);
      log.info("Wrote bytes {}", buffer);
      Thread.sleep(500);
      log.info("Flushing stream");
      outputStream.flush();
    }
  } catch (IOException | InterruptedException e) {
    log.error("Received exception: {}", e.getClass().getSimpleName());
  }
}
解决方案

要让浏览器和Postman实时接收分块内容,需正确配置HTTP分块传输编码并规避容器层缓冲,具体修改点如下:

  • 启用分块传输编码
    在方法开头添加响应头配置,明确告知客户端采用分块传输:

    response.setContentType("text/plain"); // 根据实际场景调整,比如模拟JSON用application/json
    response.setHeader("Transfer-Encoding", "chunked");
    response.setBufferSize(readBufSize); // 强制容器缓冲区大小与分块一致,避免缓冲
    

    注意:不要设置Content-Length头,分块传输不需要该字段,否则容器会自动缓冲所有内容直到生成完毕。

  • 修复数据流读取逻辑
    原代码中inputStream.read()无法保证每次读取指定长度的字节,需处理实际读取的字节数:

    int bytesRead = inputStream.read(buffer, 0, readBufSize - 1);
    if (bytesRead == -1) {
        break; // 数据流结束,退出循环
    }
    buffer[bytesRead] = '\n'; // 在实际读取的字节后添加换行,而非固定位置
    outputStream.write(buffer, 0, bytesRead + 1); // 只写入有效字节
    
  • 规避容器额外缓冲
    部分Spring Boot容器(如Tomcat)默认存在响应缓冲,response.setBufferSize(readBufSize)可强制容器不缓冲超过指定大小的内容,配合flush()操作就能实时输出分块。

  • 适配测试工具特性

    • Postman:切换到“Stream”模式查看响应,关闭可能导致缓冲的自动重定向等设置;
    • 浏览器:部分浏览器会缓冲文本内容直到换行或达到一定大小,添加\n分隔块是合理做法,若模拟JSON需保证分块是合法的JSON片段或整体结构的一部分。
修改后的完整代码
private static final int readBufSize = 10;
  
private static final int generatedStringSize = readBufSize * 10000;

@GetMapping(path = "/v2/payload/mocklargepayload")
public void simulateLargePayload(HttpServletResponse response){
  try {
    // 配置分块传输响应头
    response.setContentType("text/plain");
    response.setHeader("Transfer-Encoding", "chunked");
    response.setBufferSize(readBufSize);

    try(InputStream inputStream = IOUtils.toInputStream(RandomStringUtils.randomAlphanumeric(generatedStringSize));
        OutputStream outputStream = response.getOutputStream()) {
      final byte[] buffer = new byte[readBufSize];
      for(int i = 0; i < generatedStringSize; i+= readBufSize){
        int bytesRead = inputStream.read(buffer, 0, readBufSize - 1);
        if (bytesRead == -1) {
            break;
        }
        buffer[bytesRead] = '\n';
        log.info("Read bytes: {}", new String(buffer, 0, bytesRead + 1));
        outputStream.write(buffer, 0, bytesRead + 1);
        log.info("Wrote bytes {}", new String(buffer, 0, bytesRead + 1));
        Thread.sleep(500);
        log.info("Flushing stream");
        outputStream.flush();
      }
    }
  } catch (IOException | InterruptedException e) {
    log.error("Received exception: {}", e.getClass().getSimpleName());
  }
}

内容的提问来源于stack exchange,提问作者Jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 10:25:17