使用Axios流式下载PDF后FormData上传MIME类型异常问题
我用Axios以responseType=stream的方式从S3获取PDF文件流,代码如下:
module.exports.getStream = (fileURL) => { return Axios({ method: 'get', url: fileURL, responseType: 'stream', }).then(response => { return response.data; }); };
随后将该文件流传入form-data库构建的FormData,上传到第三方服务:
const formData = new FormData(); formData.append("file", await getStream(URL));
上传流程能正常执行,但第三方返回错误,称文件MIME类型为application/octet-stream,不符合仅允许application/pdf、application/acrobat、application/nappdf的要求。实际原文件的Content-Type已在S3正确设置为application/pdf,且用相同代码下载部分文件时,生成的流MIME类型显示为application/pdf,而非application/octet-stream。
问题原因
当直接将Axios返回的流传给formData.append()时,form-data库无法自动从流中读取原文件的Content-Type信息,因此默认使用通用的application/octet-stream作为文件的MIME类型,导致第三方服务校验失败。
而下载文件时显示正确的MIME类型,是因为下载流程中会读取Axios响应头里的content-type字段,并将其应用到输出响应或文件保存配置中,但上传时没有将这个信息传递给FormData。
解决方案
修改代码,从Axios的响应头中获取正确的Content-Type,在构建FormData时手动指定文件的MIME类型和文件名:
- 调整
getStream函数,同时返回文件流、Content-Type和文件名:
module.exports.getStream = async (fileURL) => { const response = await Axios({ method: 'get', url: fileURL, responseType: 'stream', }); // 从响应头或URL末尾提取文件名 const filename = response.headers['content-disposition'] ? response.headers['content-disposition'].split('filename=')[1].replace(/["']/g, '') : fileURL.split('/').pop(); return { stream: response.data, contentType: response.headers['content-type'], filename: filename }; };
- 上传时,将这些信息传递给FormData的
append方法:
const { stream, contentType, filename } = await getStream(URL); const formData = new FormData(); formData.append("file", stream, { filename: filename, contentType: contentType });
这样FormData就会携带正确的MIME类型,第三方服务就能识别出文件为PDF类型,通过校验。
内容的提问来源于stack exchange,提问作者DomingoSL

