GET/POST下载文件傻傻分不清?SpringBoot+Vue实战解析,前端别再问我了!

311 阅读4分钟

@TOC

前言

前端同事:“POST下载文件怎么接收?” 我:“???” 这问题,就像问“用筷子怎么喝汤”一样让人哭笑不得! 不过,既然有人问,那我就来当一回“科普达人”,给大家讲讲GET/POST下载文件的区别,保证让你听得津津有味,还能学到真本事!

在这里插入图片描述

一、GET下载文件:简单直接,但并非万能

  • 使用场景:GET方法一般用于请求数据时,适用于通过URL直接传递下载的文件标识(如文件ID、文件名等)。如果文件本身比较小,并且参数量不大,使用GET方法通常是合适的。
  • 优点:方法简单,适合一些简单的文件下载,浏览器通常也会直接支持GET请求的文件下载。
  • 缺点:请求URL长度有限制,不能传输过多的参数,安全性低。如果下载的文件需要传递复杂的请求参数(如多个ID),POST可能会更加合适。

1.1 前端示例代码

// 前端:使用 GET 请求下载文件
function downloadFile() {
  const fileId = "5356ad47a3754d56a1929e6224aa2fac";
  const url = `/manage/downloadFile?id=${fileId}`; // 通过URL传递文件ID
  const link = document.createElement('a');
  link.href = url;
  link.download = "temp.zip";  // 设置默认的下载文件名
  link.click();
}

1.2 后端示例代码

@GetMapping("/downloadFile")
public ResponseEntity<Resource> downloadFile(@RequestParam String id) {
    // 根据文件ID获取文件路径
    String filePath = getFilePathById(id);
    File file = new File(filePath);
    
    if (!file.exists()) {
        throw new ResponseStatusException(HttpStatus.NOT_FOUND, "File not found");
    }

    // 设置响应头
    HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
    headers.add(HttpHeaders.CONTENT_TYPE, "application/zip");
    
    Resource resource = new FileSystemResource(file);
    return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

二、POST下载文件:低调奢华,暗藏玄机

  • 使用场景:POST方法适用于文件下载时,参数较多或需要发送较复杂的数据(如文件ID、用户认证信息等)。POST请求没有URL长度限制,适合传递大量参数或大数据量。
  • 优点:POST方法可以通过请求体发送大量数据,适合多参数的复杂查询,安全性较高。且可以通过请求头传递额外的认证信息或自定义参数。
  • 缺点:通常情况下,文件下载使用POST方法略显复杂,但如果你的需求涉及到传递很多数据或需要隐式传输参数,POST可能更适合

1.1 前端示例代码

// 前端:使用 POST 请求下载文件
function downloadFiles() {
  const params = {
    ids: ["5356ad47a3754d56a1929e6224aa2fac", "5356ad47a3754d56a1929e6224aa2faq"]
  };

  axios.post('/manage/batchDownload', params, { responseType: 'blob' })
    .then((res) => {
      // 创建一个Blob对象,并用URL.createObjectURL生成下载链接
      const blob = res;
      if(blob && blob instanceof Blob) {
          const link = document.createElement('a');
          const filename = `${Date.now()}_temp.zip`;
          const url = window.URL.createObjectURL(blob);
          link.href = url;
          link.download = filename; 
          link.click();
          window.URL.revokeObjectURL(url);
      } else {
          console.error('下载文件失败: 响应不是有效的Blob类型');
      }
    })
    .catch((error) => {
      console.error('下载文件失败:', error);
    });
}

1.2 后端示例代码

@PostMapping("/batchDownload")
public void batchDownload(@RequestBody ContractIdsV2RequestDto params, HttpServletResponse response, HttpServletResponse response) throws IOException {
    List<ContractFileInfo> fileInfoList = getFileInfoList(params.getIds());
    
    // 设置响应头
    String filename = "files.zip";
    response.setContentType("application/zip");
    response.setHeader("Content-Disposition", "attachment; filename=" + filename);
    
    // 使用 ZipOutputStream 写入文件
    try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
        for (ContractFileInfo fileInfo : fileInfoList) {
            String filePath = fileInfo.getFilePath();
            if (StringUtils.isNotBlank(filePath)) {
                try (InputStream inputStream = new FileInputStream(filePath)) {
                    ZipEntry zipEntry = new ZipEntry(fileInfo.getFileName());
                    zipOut.putNextEntry(zipEntry);
                    IOUtils.copy(inputStream, zipOut);
                    zipOut.closeEntry();
                }
            }
        }
    }
}

如何校验是否正确返回Blob对象?

  1. 打开浏览器的开发者工具(通常是按F12或Ctrl+Shift+I),切换到“Network”选项卡。
  2. 找到你的批量下载请求,查看响应内容
  3. 如果你看到的响应数据以PK(ZIP文件的头部标识)开头,那就说明后端返回了正确的ZIP文件。 如果不是,可能是后端返回了错误信息或其他内容,导致ZIP文件没有正确生成或传输。

POST请求的方法,无非就是后端处理文件之后,返回二进制数据,前端接受二进制数据从而转换下载,前端需要设置响应头为Blob:

responseType: 'blob'  // 设置返回类型为Blob对象,就是二进制数据

然后前端将Blob对象转为一个临时的URL,就可以通过浏览器来下载了。

// 创建一个Blob对象,并用URL.createObjectURL生成下载链接
const blob = res // 接收到后端返回的二进制数据;
if(blob && blob instanceof Blob) {
    const link = document.createElement('a');
    const filename = `${Date.now()}_temp.zip`;
    const url = window.URL.createObjectURL(blob);
    link.href = url;
    link.download = filename; 
    link.click();
    window.URL.revokeObjectURL(url);
} else {
    console.error('下载文件失败: 响应不是有效的Blob类型');
}

三、GET vs POST:如何选择?

GET 方法适用场景:

  • 文件ID、文件名等参数较少且可以通过URL传递。
  • 文件较小,不需要传递大量数据或复杂的认证信息。
  • 安全性要求不高的场景。

POST 方法适用场景:

  • 需要传递大量的参数或数据,如批量下载、认证信息等。

  • 文件较大,或需要对文件内容进行特殊处理(例如压缩多个文件、加密文件等)。

  • 安全性要求高的场景。

总结

还记得那个“用筷子喝汤”的比喻吗? 就像喝汤可以用勺子也可以用筷子,下载文件也可以用GET或者POST,关键是要选对“工具”!

  • GET 就像勺子,简单直接,舀起汤来毫不费力,但遇到“大块头”就有点力不从心。
  • POST 就像筷子,虽然上手难度高一点,但夹起“大块头”来游刃有余,还能玩出各种花样。

所以,下次再遇到文件下载的需求,别再纠结用勺子还是筷子啦! 根据实际情况,选择合适的“工具”,才能优雅地“享用”你的文件大餐!

最后,友情提示: 千万别试图用GET下载一个比你家房子还大的文件,否则…… 你懂的! 😉