指定文件下载的处理方式都归结于
Content-disposition
头。您也可以在这里指定文件的名称。我们还设置了
Content-type
,以确保浏览器知道如何处理给它的文件。
app.post('/url/to/hit', function(req, res, next) {
var stream = fs.createReadStream('/location/of/pdf');
var filename = "WhateverFilenameYouWant.pdf";
filename = encodeURIComponent(filename);
res.setHeader('Content-disposition', 'inline; filename="' + filename + '"');
res.setHeader('Content-type', 'application/pdf');
stream.pipe(res);
});
现在,如果你更仔细地查看
Content-disposition
,你会注意到
inline;
字段是设置浏览器对文件反应的方式。如果你想强制下载,可以将
inline;
设置为
attachment;
我也发现(通过几次被烧伤),如果你在文件名中设置特殊字符,它可能会出错。所以我使用
encodeURIComponent()
对文件名进行了编码,以确保不会发生这种情况。
希望这能帮助其他试图解决同样问题的人!
编辑
在我最初发布这篇文章和现在之间的时间里,我已经发现了如何正确编码
content-disposition
的文件名参数。根据规范,文件名应该是RFC5987编码。我最终在MDN上找到了一个示例代码片段,它正确处理了编码(
encodeURIComponent()
并不是这个字段的完全正确格式)。
链接1 链接2
MDN片段
var fileName = 'my file(2).txt';
var header = "Content-Disposition: attachment; filename*=UTF-8''"
+ encodeRFC5987ValueChars(fileName);
console.log(header);
function encodeRFC5987ValueChars (str) {
return encodeURIComponent(str).
replace(/['()]/g, escape).
replace(/\*/g, '%2A').
replace(/%(?:7C|60|5E)/g, unescape);
}
除此之外,需要注意的是,浏览器也没有完全遵守规范。有些字符在下载时仍然会出现错误(至少在我的测试中是这样的)。
您可以通过更新下载方式来解决这个问题。如果您的下载URL以文件名结尾(并且您没有在头部提供filename
属性),它将从URL编码值中正确获取文件名。例如,在IE中:'http://subdomain.domain-url.com/some/path/to/downloads/' + encodeURIComponent("You're there, download this!.pdf")
哎呀,所有这些只是为了提供一个文件名给您的下载!
response.end(data)
; Express的send
方法可能会进行某些猜测。 - ebohlman