Express res.download()函数调用失效,浏览器直接访问API正常
解决Axios调用文件下载接口无反应的问题
核心原因
直接通过浏览器访问API能触发下载,是因为浏览器会识别响应头中的Content-Disposition和文件类型,自动启动下载流程。但Axios发起请求时,只是将响应数据以二进制流形式接收,不会主动触发浏览器的下载行为,这就是按钮点击无反应的关键所在。
前端代码修复
修改downloadFile函数,指定响应类型为blob,并手动创建下载链接触发浏览器下载:
async downloadFile(name) { // 改用axios.get而非$get,避免自动解析JSON const response = await this.$axios.get(process.env.API_LINK + '/api/files/' + name, { responseType: 'blob' // 明确指定响应为二进制流 }); // 基于响应数据创建Blob对象 const blob = new Blob([response.data], { type: response.headers['content-type'] || 'application/octet-stream' }); // 创建临时下载链接 const downloadUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = downloadUrl; // 从响应头提取文件名,兜底使用传入的name const fileName = response.headers['content-disposition']?.split('filename=')[1] || name; link.download = decodeURIComponent(fileName); // 解码防止中文文件名乱码 // 触发点击下载 document.body.appendChild(link); link.click(); // 清理临时资源 window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(link); }
后端代码优化
确保响应头正确设置Content-Disposition,同时增加文件存在性检查:
const path = require('path'); const fs = require('fs'); app.get('/api/files/:name', (req, res) => { const filePath = path.join(__dirname, '..', 'files', req.params.name); // 先校验文件是否存在 fs.access(filePath, fs.constants.F_OK, (err) => { if (err) { console.error('文件不存在:', err); return res.status(404).send('请求的文件不存在'); } // 设置响应头,指定下载文件名(处理中文编码) res.setHeader( 'Content-Disposition', `attachment; filename="${encodeURIComponent(req.params.name)}"` ); // 触发文件下载 res.download(filePath, (err) => { if (err) { console.error('下载过程出错:', err); res.status(500).send('文件下载失败'); } }); }); });
关键注意点
- 不要使用
$axios.$get:这个方法会自动将响应解析为JSON,无法处理二进制文件流,必须用axios.get并指定responseType: 'blob'。 - 手动触发下载:Axios不会像浏览器那样自动处理下载,必须通过创建
<a>标签模拟点击来触发。 - 文件名编码:对文件名进行
encodeURIComponent和decodeURIComponent处理,避免中文或特殊字符导致的文件名乱码问题。
内容的提问来源于stack exchange,提问作者xadun
相关产品推荐
相关产品推荐

