Express中使用sendFile()方法时如何正确设置自定义文件名
问题根因
三种写法失效的核心问题如下:
- 方式1中
Content-Disposition使用attachment参数,该参数的作用就是强制浏览器触发附件下载,和浏览器内预览的需求冲突,同时未对文件名做编码适配,遇到中文、特殊字符时会解析失败 - 方式2、3中设置的自定义
filename头、自定义业务头不属于HTTP标准中约定的文件名识别字段,浏览器不会读取这类字段的值,默认会取请求URL路径的最后一段作为文件名。res.download方法本质也是封装了attachment类型的Content-Disposition头,所以才会强制触发下载。
实现方法
要实现「支持PDF/图片等格式浏览器内预览 + 自定义文件名(包括右键另存为的默认文件名、无法预览时的下载文件名)」,不需要替换sendFile方法,也不需要按文件扩展名做分支判断,只需要将Content-Disposition的类型从attachment改为inline即可,inline是HTTP标准中约定的「优先内嵌预览」指令。
为了兼容所有现代浏览器对中文、特殊字符文件名的解析,需要对文件名做标准编码处理,参考代码如下:
const targetPath = path.resolve(process.env.FILE_PATH, result.PATH); // 对文件名做URL编码,适配非ASCII字符、空格、特殊符号 const encodedFileName = encodeURIComponent(result.NAME); // 设置inline模式的响应头,filename*参数适配RFC 5987标准,覆盖所有现代浏览器 res.setHeader( 'Content-Disposition', `inline; filename="${encodedFileName}"; filename*=UTF-8''${encodedFileName}` ); res.sendFile(targetPath);
说明
- 该写法对所有文件类型统一生效:浏览器支持预览的格式(PDF、图片、视频、纯文本等)会直接在页面内打开,用户右键选择「另存为」时会默认使用你设置的文件名;浏览器无法识别预览的格式会自动触发下载,同样使用指定的文件名
sendFile方法不会覆盖你提前手动设置的合法Content-Disposition头,不需要把该头部写到sendFile的options配置中,提前设置即可- 不要自定义非标准的文件名相关头部,所有现代浏览器只会从标准
Content-Disposition字段中读取文件名信息
内容的提问来源于stack exchange,提问作者rhrhgut
相关产品推荐
相关产品推荐

