首页 > 解决方案 > 需要分块下载大文件

问题描述

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

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

我将文件保存在数据库中。当我收到下载文件的请求时。我将从数据库中获取文件。我将字节码推送到响应正文中并将其发送到浏览器。在浏览器中,我创建了一个链接并一次性下载文件。

后端代码:

  @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()));
  }

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

标签: javarestfilespring-boot

解决方案


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

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));
}

虽然这会给你一个分块的响应,但我不相信这是你浏览器问题的根源,因为无论服务器如何提供数据,它们都非常有能力异步流回数据。


推荐阅读