通过ajax下载文件

6

我需要通过ajax从服务器下载文件。问题在于这个文件并没有存储在服务器上。我的基于Java的后端会根据请求参数自动生成文件,并将其放在响应体中返回:

  @RequestMapping(value = "/download", method = RequestMethod.GET)
  public void download(@RequestParam String description, @RequestParam Long logId, HttpServletResponse response) {
    try {
      InputStream fileContent = // getting file as byte stream
      response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
      response.setHeader("Content-Disposition", "attachment; filename=file.zip");
      ServletOutputStream responseOutputStream = response.getOutputStream();
      org.apache.commons.io.IOUtils.copy(fileContent, responseOutputStream);
      response.flushBuffer();
    } catch (IOException e) {
      logger.error("Attempt to download file failed", e);
    }
  }

所以我需要处理它并允许用户下载文件。 我的客户端包含以下内容:
$.ajax({
  type: "GET",
  url: "/download",
  data: {
    description: "test",
    logId: 123
  },
  success: function(data) {
    var blob = new Blob([data]);
    var link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = "file.zip";
    link.click();
  }
})

控制器返回文件,但是什么也没有发生。我做错了什么?

2个回答

6
不要进行 AJAX 调用,而是将窗口的 href 设置为指向下载文件的 URL。然后将响应的内容类型更改为 application/x-download,并将响应的头设置为 Content-disposition
response.setContentType("application/x-download");
response.setHeader("Content-disposition", "attachment; filename=" + fileName);
response.flushBuffer();

function download(fileName) {
    window.location.href = "/download?description=test&logId=123";
}

此外,请查看此SO帖子,它解决了与您遇到的类似问题。

2
好的,但如果我想要使用POST请求而不是GET请求,并传递一个很长的字符串参数,我需要做什么? - Everv0id
这种方法对于POST不起作用。但是你为什么现在改变你的问题呢? - Tim Biegeleisen
4
你的回答在我的特定情况下完美地运作。我只是想深入了解。 - Everv0id

4

对于那些希望采用更现代方法的人来说,你可以使用 fetch API。下面的示例展示了如何下载一个 PDF 文件。这可以通过以下代码轻松完成。

fetch(url, {
    body: JSON.stringify(data),
    method: 'POST',
    headers: {
        'Content-Type': 'application/json; charset=utf-8'
    },
})
.then(response => response.blob())
.then(response => {
    const blob = new Blob([response], {type: 'application/pdf'});
    const downloadUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = downloadUrl;
    a.download = "file.pdf";
    document.body.appendChild(a);
    a.click();
})

我认为这种方法比其他XMLHttpRequest解决方案更容易理解。此外,它具有类似于jQuery方法的语法,无需添加任何额外的库。

当然,我建议您检查您正在开发的浏览器,因为这种新方法在IE上不起作用。您可以在以下[链接][1]中找到完整的浏览器兼容性列表。

重要提示:在这个例子中,我向一个监听给定url的服务器发送JSON请求。这个url必须被设置,在我的例子中,我假设你知道这一部分。还要考虑需要您的请求工作的标头。由于我正在发送JSON,我必须添加Content-Type标头并将其设置为application/json; charset=utf-8,以便让服务器知道它将收到的请求类型。

重要提示:使用fetch API发送参数到“GET”请求将需要使用URLSearchParams接口。


1
是的,这个完美地运作了。你可以通过ajax发送一个普通的GET请求,在后端你必须确保以适当的content-type(例如application/pdf)发送文件作为响应。在我的情况下,我使用了Axios,并将responseType设置为Blob,它会自动使用提供的Content-Type。如果您希望重复使用“点击”按钮,则也可以事先设置它。 - OzzyTheGiant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接