以块的形式提供数据的Spring端点

kuuvgm7e  于 2023-02-21  发布在  Spring
关注(0)|答案(1)|浏览(96)

在我的团队中,我们遇到了一个特定端点的问题,当使用一些特定参数调用该端点时,它会提供一个巨大的JSON块。因此,例如,如果JSON有1,000行,在使用浏览器打开URL大约30秒后(这是一个GET端点)我们得到100行,然后再等几行,得到下一个200行,等等,直到JSON耗尽为止。这对我们来说是个问题,因为我们的应用程序在检索JSON之前超时。我们希望用我们自己的示例端点来模拟端点的行为,用于调试目的。
到目前为止,我已经完成了以下操作。为了简单起见,我甚至没有阅读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());
    }
  }
n9vozmp4

n9vozmp41#

你的端点应该返回一个标头"content-length",在这里你将指定端点返回的信息的总大小。这将通知你的客户端需要多少信息。另外,你可以在信息可用时逐块读取信息。我遇到了一个相反的问题,我在端点中写入了一个很大的输入(POST)。端点读取它的速度比我写的速度快,所以在某个时候,当它读取到目前为止所有可用的信息时,它会停止读取,认为这就是它。所以,我写了下面的代码,你可以在客户端以同样的方式实现它:

@PostMapping
public ResponseEntity<String> uploadTest(HttpServletRequest request) {
    try {
        String lengthStr = request.getHeader("content-length");
        int length = TextUtils.parseStringToInt(lengthStr, -1);
        if(length > 0) {
            byte[] buff = new byte[length];
            ServletInputStream sis =request.getInputStream();
            int counter = 0;
            while(counter < length) {
                int chunkLength = sis.available();
                byte[] chunk = new byte[chunkLength];
                sis.read(chunk);
                for(int i = counter, j= 0; i < counter + chunkLength; i++, j++) {
                    buff[i] = chunk[j];
                }
                counter += chunkLength;
                if(counter < length) {
                    TimeUtils.sleepFor(5, TimeUnit.MILLISECONDS);
                }
            }
            Files.write(Paths.get("C:\\Michael\\tmp\\testPic.jpg"), buff);
        }
    } catch (Exception e) {
        System.out.println(TextUtils.getStacktrace(e));
    }
    return ResponseEntity.ok("Success");
}

另外,我为读/写编写了一个通用特性,也遇到了同样的问题(同样适用于服务器端),但同样你也可以在客户端实现相同的逻辑。该特性在信息可用时读取信息块。该特性随开源库MgntUtils提供(由我编写和维护)。参见类WebUtils。包含源代码和Javadoc的库可以在Github here. Javadoc is here上获得。它也可以作为Maven artifact here获得

相关问题