You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Axios或XHR通过预签名S3 PUT URL上传二进制图片?

如何使用Axios或XHR通过预签名S3 PUT URL上传二进制图片?

现有代码与测试情况

1. 生成S3预签名URL的代码

const file = req.files ? req.files.filename || null : null
const extension = path.extname(file.name)
const client = new S3Client()

const params = {
  Bucket: S3_BUCKET, // 环境变量
  Key: `tmp/photos/image_file.png`,
  ContentDisposition: 'inline',
  ContentType: file.mimetype,
  Body: file.data
}

const command = new PutObjectCommand(params)
const presignedS3Url = await getSignedUrl(client, command, { expiresIn: 3600 })

可正常工作的CURL请求

curl --location --request PUT $presignedS3Url \
--header 'Content-Disposition: inline' \
--header 'Content-Type: image/png' \
--data-binary '@/Users/name/Downloads/image-file.png'

失败的Axios尝试代码

const imageFile = fs.readFile('/Users/filepath/image-file.png')
const bufferString = Buffer.from(imageFile, 'base64')

await axios.put(presignedS3Url, {
  data: bufferString
}, {
  headers: {
    'Content-Type': file.mimetype,
    'Content-Disposition': 'inline'
  }
})

解决方案

修复Axios上传代码

你的Axios代码存在两个关键问题:

  1. fs.readFile是异步方法,直接赋值会得到Promise而非文件内容,需改用同步读取或异步等待;
  2. 上传时无需把数据包装在{ data: bufferString }里,直接传递二进制数据作为请求体即可。

修复后的同步读取版本:

const imageBuffer = fs.readFileSync('/Users/filepath/image-file.png')

await axios.put(presignedS3Url, imageBuffer, {
  headers: {
    'Content-Type': 'image/png', // 需与预签名URL生成时的ContentType一致
    'Content-Disposition': 'inline'
  }
})

异步读取版本:

const imageBuffer = await fs.promises.readFile('/Users/filepath/image-file.png')

await axios.put(presignedS3Url, imageBuffer, {
  headers: {
    'Content-Type': 'image/png',
    'Content-Disposition': 'inline'
  }
})

使用XHR上传的方法

如果用原生XHR实现,代码示例如下:

const xhr = new XMLHttpRequest()
xhr.open('PUT', presignedS3Url, true)

xhr.setRequestHeader('Content-Type', 'image/png')
xhr.setRequestHeader('Content-Disposition', 'inline')

// 以浏览器input文件为例
const fileInput = document.querySelector('input[type="file"]')
const file = fileInput.files[0]

xhr.send(file)

// 监听上传状态
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log('上传成功')
  } else {
    console.error('上传失败', xhr.responseText)
  }
}

关键注意事项

  • 预签名URL生成时指定的ContentType必须和上传请求头的Content-Type完全一致,S3会严格验证这一点;
  • 上传的二进制数据需为原始文件内容,无需转base64(除非预签名时明确指定了对应编码);
  • 浏览器环境下使用Axios时,直接传递File对象或ArrayBuffer作为请求体即可,无需处理Buffer。

内容的提问来源于stack exchange,提问作者kush patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 10:33:47