记一次golang结合前端的axios进行预签名分片上传遇到403签名错误踩坑
问题背景
在开发一个基于阿里云OSS大文件上传功能时,技术栈采用Golang作为后端语言,配合阿里云OSS V2版SDK,前端使用Vue和Axios。项目需求要求实现大文件分片上传至OSS的功能,但在实际开发过程中遇到了签名验证失败的问题。
技术环境
后端使用Golang编写,调用阿里云OSS官方提供的V2版本SDK生成预签名URL。前端使用Vue框架搭配Axios库发起文件上传请求。OSS存储桶的权限配置已经正确设置,确保了PutObject
操作的合法性。
问题现象
前端通过Axios获取到后端生成的预签名URL后,尝试上传文件时,OSS服务端返回403错误,提示签名不匹配。检查发现签名生成逻辑和权限配置均无异常,但所有请求均携带了默认的Content-Type: application/x-www-form-urlencoded
请求头,而该请求头未被包含在签名计算中。
排查过程
- 基础检查:确认OSS存储桶的CORS配置允许前端域名,且
PutObject
权限已正确赋权。 - 签名验证:对比签名生成逻辑与阿里云官方文档,确认签名算法未遗漏必要参数。
- 请求头分析:通过抓包工具发现Axios自动添加的
Content-Type
头未被包含在签名计算中,导致服务端验签失败。 - SDK限制:检查阿里云OSS V2版SDK发现,签名生成接口未提供请求头定制化选项,无法将
Content-Type
纳入签名计算。
关键发现
阿里云OSS的签名机制要求所有参与签名的请求头必须与服务端计算的签名完全一致。Axios的默认行为会自动添加Content-Type: application/x-www-form-urlencoded
头,而该头未被包含在后端生成的签名中,导致服务端验签失败。
解决方案探索
尝试通过以下方式解决问题:
- 修改Axios配置:试图取消默认的
Content-Type
头,发现Axios在部分版本中无法完全移除该头。 - 调整签名逻辑:强制后端在生成签名时包含该请求头,但受限于SDK设计无法实现。
- 自定义请求库:考虑替换Axios为其他可精细控制请求头的库,但成本较高。
- 服务端代理上传:改为由后端直接接收文件再上传至OSS,牺牲了前端直传的性能优势。
经过排查和阿里云客服的反馈,发现前端Axios默认会添加'Content-Type': 'application/x-www-form-urlencoded'
的Header,而后端生成的签名未包含此Header,导致签名验证失败。由于阿里云OSS的签名机制要求请求的Header必须与签名时完全一致,因此多出的Header会导致403错误。
解决方案
最后还是在axios上下功夫得以解决(本来都想放弃axios改用原生的方案了,尝试了几种方案最后终于把这个磨人的header去掉了),示例代码如下:
const response = await axios({method,url: uploadUrl,data: partBlob,transformRequest: [(data, headers) => {// 确保 Content-Type 头部被删除delete headers.put['Content-Type']return data}],onUploadProgress: (progressEvent) => {}})
总结
该问题的核心在于签名与请求Header的不一致。通过调整后端签名逻辑或前端请求配置,可以解决这一问题。如果问题复杂,预签名URL是一种更灵活的替代方案。