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

使用Axios通过预签名链接上传图片至DigitalOcean Spaces时遇SignatureDoesNotMatch错误

解决Axios上传DigitalOcean Spaces时的“Signature Does Not Match”错误

我刚踩过几乎一模一样的坑!既然XMLHttpRequest能正常工作,那问题肯定出在Axios对请求的默认处理逻辑上——DigitalOcean Spaces(兼容S3的签名机制)对请求细节的校验非常严格,哪怕一个请求头或者请求体的微小差异都会导致签名不匹配。

下面是几个最可能的原因和对应的解决办法:

1. Axios自动添加的Content-Type与预签名URL不匹配

生成预签名URL时,你应该指定了具体的Content-Type(比如image/png),但Axios会默认给请求加上Content-Type: application/json,或者根据FormData自动生成带边界符的类型,这和你生成签名时的预设完全不一致,直接触发签名校验失败。

解决办法:手动设置和签名生成时完全一致的Content-Type,并且禁用Axios的自动头处理:

// 假设你获取到的图片文件是imageFile
axios.put(presignedUrl, imageFile, {
  headers: {
    'Content-Type': imageFile.type, // 必须和生成预签名URL时的Content-Type完全一致
  },
  transformRequest: (data, headers) => {
    // 移除Axios自动添加的通用Content-Type
    delete headers.common['Content-Type'];
    return data;
  }
})

2. 用FormData导致请求体多了边界符

XMLHttpRequest直接上传文件二进制时,请求体就是纯文件内容;但Axios用FormData的话,会自动给请求体加上边界分隔符,而你的预签名URL是基于纯二进制数据生成的,这就导致签名校验不通过。

解决办法:不要用FormData,直接上传文件的二进制/Blob数据:

// 在React Native中可以用react-native-fs读取文件为Blob
import RNFS from 'react-native-fs';

const fileBase64 = await RNFS.readFile(imagePath, 'base64');
const fileBlob = new Blob([fileBase64], { type: imageFile.type });

axios.put(presignedUrl, fileBlob, {
  headers: {
    'Content-Type': imageFile.type,
  },
  transformRequest: [data => data] // 禁用Axios的自动数据转换
})

3. Axios的自动数据转换破坏了原始内容

Axios默认会对请求数据做转换(比如把对象转成JSON),这种转换会改变二进制文件的原始内容,导致签名和实际请求体不匹配。

解决办法:显式禁用请求转换:

axios.put(presignedUrl, fileBlob, {
  headers: {
    'Content-Type': imageFile.type,
  },
  transformRequest: [data => data] // 让Axios直接传递原始数据
})

验证步骤

如果还是不行,建议抓包对比Axios和XMLHttpRequest的请求:

  • 检查请求头:确保所有头信息(尤其是Content-Type)完全一致
  • 检查请求体:看Axios是否给请求体加了额外的内容(比如FormData的边界符)
  • 确认生成预签名URL时的参数(HTTP方法、Content-Type、过期时间)和Axios请求的完全一致,大小写都不能错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:40:34