如何使用Axios以binary/octet-stream格式上传File对象至S3存储桶
问题背景
开发目标为将input标签获取到的文件上传至S3存储桶,需将类型为[Object file]的文件对象转换为请求头Content-Type: binary/octet-stream支持的传输格式。此前尝试使用Buffer.from()、.toString("base64")等方法处理文件,均未生效。
当前使用的API请求代码如下:
export async function sendToS3(uploadURL, file) { let request = { method: "PUT", url: uploadURL, headers: { "Content-Type": "binary/octet-stream", }, data: file }; const response = await axios(request); return response.data; };
从input标签获取到的待上传File对象结构如下:
File { name: "filename.jpg", lastModified: "1652758134934", size: "64058", type: "image/jpeg", webkitRelativePath: "folderName/filename.jpg" }
可行方案
之前方法失效的核心原因:浏览器环境下axios会默认对传入的data做表单序列化处理,最终发送的请求体不是S3要求的原始二进制流;另外Buffer.from()是Node.js专属API,浏览器端polyfill实现容易出现格式偏差,base64编码会改变文件原始二进制内容,和签名时指定的binary/octet-stream格式不匹配,自然会上传失败。
直接用下面的代码即可,不需要额外做格式转换:
export async function sendToS3(uploadURL, file) { const request = { method: "PUT", url: uploadURL, headers: { "Content-Type": "binary/octet-stream", }, data: file, // 关键配置:禁用axios默认的请求体序列化逻辑,直接透传原始二进制数据 transformRequest: [(data) => data] }; const response = await axios(request); return response.data; }
如果遇到兼容性问题,就先把File转成ArrayBuffer再传入,适配所有现代浏览器:
export async function sendToS3(uploadURL, file) { // File本身是Blob的子类,可直接调用arrayBuffer()方法读取原始二进制内容 const fileBuffer = await file.arrayBuffer(); const request = { method: "PUT", url: uploadURL, headers: { "Content-Type": "binary/octet-stream", }, data: fileBuffer, transformRequest: [(data) => data] }; const response = await axios(request); return response.data; }
注意事项
- 不要手动添加
Content-Length请求头,浏览器上传时会自动计算填充,手动添加容易触发跨域预检失败 - 不要对文件做base64编码,base64编码后的内容比原文件大33%,且内容格式和签名要求的二进制流不匹配,会触发S3签名校验错误
- 如果是用预签名URL上传,生成预签名URL时指定的
Content-Type必须和上传请求头里的值完全一致,否则会报403权限错误
内容的提问来源于stack exchange,提问作者CxrlosKenobi
相关产品推荐
相关产品推荐

