Content-Disposition: attachment未触发下载对话框。

21

当我试图在我的NodeJS服务器上创建文件下载功能时,遇到了一些意外的行为。我有一个REST(express)API调用一些导出数据函数,它会在服务器上创建一个CSV文件并使用res.download('path/to/file')触发下载。响应头包括

Content-Disposition:attachment; filename="indicators.csv"
Content-Length:30125
Content-Type:text/csv; charset=UTF-8

看起来一切都很顺利。

问题是,我从服务器得到的响应是纯文本。响应中包含了CSV文件中的所有数据,但并没有像我预期的那样触发浏览器的文件下载对话框。 我在Chrome和FF上都尝试过了,问题仍然存在。

有什么想法吗?

更新

我通过创建一个虚拟表单,并使用其提交操作来进行AJAX调用,成功实现了目标。但这是一个不太优雅的hack,我仍在寻找更加优美的解决方案。

4个回答

34

头部信息并不是问题所在。问题在于您正在通过ajax调用查询下载网址,这将不会触发浏览器的下载对话框。您有以下几个选项:

  1. 使用一个提交到您的下载 URL 的表单。不需要用户互动,创建一个带有JavaScript的表单,并通过调用form.submit进行程序化提交 - 从 Ajax 发布处理文件下载

  2. window.location指向下载网址。您可以在当前窗口中执行此操作 - 使用 Ajax 请求下载文件,或者在新窗口中 - res.download() 在我的情况下无法工作


正如您在我的问题中所看到的,我最终使用了选项1。但是我必须承认,在我的情况下,选项2可能是更优雅的解决方案。 - Yaron Schwimmer
这两个在Safari上表现如何?我发现它们都被视为弹出窗口,并在Safari中对用户有效地隐藏。 - Jordan Mackie

1
你可以尝试使用不同的内容类型,这样在浏览器上就不会以文本文件形式打开:
Content-Type:application/ms-excel; charset=UTF-8

另一个选择是使用application/octet-stream作为MIME类型,以将其定义为可下载文件而没有更好的描述。

Content-Type:application/octet-stream; charset=UTF-8

0
受Roman Pletnev的启发,我建议将API响应封装到一个虚构的新文档中,如下所示(Vue/csv响应):
    API.get(apiName, path, myInit)
        .then((response) => {
            // console.log(response)
            // Wrap this response into a temporary page that will trigger the download
            const blob = new Blob([response.data], { type: 'text/csv' })
            const blobURL = window.URL.createObjectURL(blob)
            const tempLink = document.createElement('a')
            tempLink.style.display = 'none'
            tempLink.href = blobURL
            tempLink.download = 'filename.csv'
            tempLink.setAttribute('target', '_blank')
            document.body.appendChild(tempLink)
            tempLink.click()
            document.body.removeChild(tempLink)
            window.URL.revokeObjectURL(blobURL)
        })
        .catch((error) => {
            console.log(error)
            console.log(error.response);
        });

0

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