需要分块下载大文件

时间:2019-09-03 05:50:10

标签: java rest file spring-boot

我有20 MB的文件。我只想在浏览器中以块/流的形式下载文件,这样,如果有另一个请求,很长一段时间内不会被阻止。

我还在长文件中看到了暂停行为。现在不需要。如果有人因为我好奇而知道这是如何工作的,可以解释一下。

我已将文件保存在DB中。当我收到下载文件的请求时。我将从DB获得文件。我将字节代码推入响应主体并将其发送到浏览器。在浏览器中,我创建了一个链接,并一次性下载了文件。

后端代码:

  @GetMapping("/job-detail/{jobExecutionId}/file-detail")
  public ResponseEntity<Resource> getFileDetail(@PathVariable final Long jobExecutionId) {
    final FileDetailDto fileDetailDto =
        fileTaskletService.getFileDetailByExecutionId(jobExecutionId);

    return ResponseEntity.ok().contentType(new MediaType("text", "csv"))
        .header(HttpHeaders.CONTENT_DISPOSITION,
            "attachment; filename=\"" + fileDetailDto.getFileName() + "\"")
        .body(new ByteArrayResource(fileDetailDto.getData()));
  }

我想分块下载文件,以便其他请求也可以同时开始下载。

1 个答案:

答案 0 :(得分:1)

从问题的措辞看来,您希望服务器框架为您设置以下标头,以使数据以分块的形式流回:

Transfer-Encoding: chunked

要执行此操作,您需要提供Spring资源,而该资源无法预先知道完整大小。您已使用ByteArrayResource,其中已知全尺寸 并导致在响应中设置了Content-Length标头,而未使用分块。

将代码更改为使用InputStreamResource,该服务将使用分块的传输编码将响应流传输回客户端,并且没有内容长度。这是一个示例(未选中语法):

try(ByteArrayInputStream bis = new ByteArrayInputStream(fileDetailDto.getData())) {
  return ResponseEntity.ok().contentType(new MediaType("text", "csv"))
          .header(HttpHeaders.CONTENT_DISPOSITION,
              "attachment; filename=\"" + fileDetailDto.getFileName() + "\"")
          .body(new InputStreamResource(bis));
}

尽管这会给您带来分块的响应,但我不认为这是浏览器问题的根源,因为无论服务器如何提供,它们都具有异步流回数据的能力。