如何将Axios获取的stream类型响应转发给前端实现浏览器直接下载
解决方案
1. Express 服务端实现
你不需要将文件写入本地磁盘,直接把Axios返回的流式响应透传给Express的res对象即可,完整示例代码如下:
const express = require('express'); const axios = require('axios'); const app = express(); app.get('/download', async (req, res, next) => { try { const targetFileUrl = '你要请求的第三方文件地址'; // 发起Axios请求获取文件流 const axiosResponse = await axios({ method: 'GET', url: targetFileUrl, responseType: 'stream' }); // 透传第三方接口返回的响应头,也可以自定义 res.set({ // 告诉浏览器这是要下载的附件,自定义文件名 'Content-Disposition': `attachment; filename="自定义的文件名.后缀"`, // 透传第三方返回的文件类型 'Content-Type': axiosResponse.headers['content-type'], // 透传文件大小,可选 'Content-Length': axiosResponse.headers['content-length'], // 跨域场景下需添加该行,允许前端读取Content-Disposition头 'Access-Control-Expose-Headers': 'Content-Disposition' }); // 直接把文件流pipe给Express的响应对象,完成透传 axiosResponse.data.pipe(res); // 处理流传输完成的逻辑 axiosResponse.data.on('end', () => { res.end(); }); // 处理流传输错误 axiosResponse.data.on('error', (err) => { next(err); }); } catch (err) { // 处理Axios请求错误 res.status(500).send('文件下载失败'); } }); app.listen(3000);
注意:如果前端和Express服务跨域,必须添加
Access-Control-Expose-Headers: Content-Disposition响应头,否则前端无法读取到文件名配置。
2. 前端 Ajax 调用实现
因为你是通过Ajax请求接口,浏览器不会自动触发下载,需要前端手动处理blob响应生成下载触发动作,示例代码如下:
// 前端用Axios请求示例 async function downloadFile() { const response = await axios({ method: 'GET', url: 'http://你的Express服务地址/download', // 必须指定响应类型为blob responseType: 'blob' }); // 生成临时下载链接 const blobUrl = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement('a'); link.href = blobUrl; // 从响应头中获取文件名,也可以直接自定义 const fileName = response.headers['content-disposition']?.split('filename=')[1]?.replaceAll('"', '') || '默认下载文件名.后缀'; link.setAttribute('download', fileName); document.body.appendChild(link); // 触发点击下载 link.click(); // 清理临时资源 link.remove(); window.URL.revokeObjectURL(blobUrl); }
核心说明
- 整个流程没有任何本地磁盘IO操作,文件流从第三方资源到Express再到前端完全在内存中传输,不会占用服务端存储
- 方案天然支持大文件下载,流式传输不会一次性加载整个文件到服务端内存,内存占用极低
内容的提问来源于stack exchange,提问作者John doe
相关产品推荐
相关产品推荐

