通过axios中转调用上传接口时无法获取返回的可下载文件问题
中转上传接口无法返回下载文件的排查修正方案
核心问题来源
当前中转路由的实现存在3个关键疏漏,直接导致前端收不到可触发下载的文件响应:
- 调用目标上传接口后,没有把响应内容透传给前端:现有代码执行完axios请求后路由直接结束,完全没把目标接口返回的下载文件数据回写给前端的响应对象,前端拿到的是空响应,自然不会触发下载。
- axios默认响应解析会破坏二进制文件流:目标接口返回的是供下载的二进制文件,默认配置下axios会把响应当成JSON文本处理,哪怕后续补了透传逻辑,拿到的流内容也已经被解析损坏,下载下来的文件是乱码。
- 请求头配置错位:把本该属于响应头的
Content-Disposition错加到了发往目标接口的请求头中,同时手动拼接的multipart/form-data边界值很容易和实际FormData生成的边界不匹配,甚至可能导致目标接口解析请求失败。
具体修正步骤
- 调整axios请求配置
- 删掉手动设置的
Content-Type、Content-Disposition请求头,改用FormData实例自带的getHeaders()方法自动生成正确的多部分表单请求头,避免手动拼接边界值出错 - 给axios请求加上
responseType: 'stream'配置,让axios直接返回原始的文件二进制流,不做自动文本/JSON解析
- 删掉手动设置的
- 补充完整的响应透传逻辑
- 从目标接口的响应中提取关键响应头(包括文件MIME类型、附件下载标识、文件大小),设置到当前服务的响应对象上
- 直接把拿到的文件流通过管道推送给前端,完成下载响应返回
修正后的参考实现
router.post("/upload", multer.single('file'), async(req, res) => { const fileRecievedFromClient = req.file; let form = new FormData(); form.append('file', fileRecievedFromClient.buffer, fileRecievedFromClient.originalname); form.append('name', req.body.name); const targetResponse = await axios.post('http://158.108.168.11:9997/upload', form, { // 自动匹配FormData对应的请求头和boundary,无需手动拼接 headers: form.getHeaders(), // 以流形式接收目标接口返回的下载文件,避免被默认解析损坏 responseType: 'stream' }); // 透传目标接口的关键响应头,让浏览器识别出附件下载 res.setHeader('Content-Type', targetResponse.headers['content-type']); res.setHeader('Content-Disposition', targetResponse.headers['content-disposition']); res.setHeader('Content-Length', targetResponse.headers['content-length']); // 将文件流直接推送到前端响应,触发浏览器下载 targetResponse.data.pipe(res); });
额外校验点
- 测试时可以先打印目标接口返回的状态码和响应头,确认目标接口确实正常返回了带附件下载标识的文件流,排除网络拦截、跨域请求失败的问题
- 确认multer配置的是内存存储(MemoryStorage),也就是代码里能正常拿到
req.file.buffer的配置,避免因磁盘存储配置导致读不到文件buffer、FormData构造异常
内容的提问来源于stack exchange,提问作者Natthan Thatiworasiri
相关产品推荐
相关产品推荐

