React.js通过axios调用boto3预签名URL传文件遇SignatureDoesNotMatch错误
S3预签名URL上传403 SignatureDoesNotMatch问题排查与解决
我通过Python Lambda生成S3预签名PUT URL,用Postman测试上传PDF文件完全正常,但改用React结合axios上传时,返回403状态码,错误信息如下:
Code: SignatureDoesNotMatch
Message: The request signature we calculated does not match the signature you provided. Check your key and signing method
相关代码
Python Lambda生成预签名URL代码
import boto3 s3_client = boto3.client('s3') params = { 'Bucket': 'bucket_name', 'Key': 'unique_id.pdf', 'ContentType': "application/pdf" } s3_response = s3_client.generate_presigned_url(ClientMethod='put_object', Params=params, ExpiresIn=300)
React上传代码(原错误版本)
const readFileDataAsBuffer = (file) => new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (event) => { resolve(event.target.result); }; reader.onerror = (err) => { reject(err); }; reader.readAsArrayBuffer(file); }); const onFileUploadChange = async (e) => { const file = e.target.files[0]; const tempdata = await readFileDataAsBuffer(file); return axios({ method: 'put', url: presigned_url_link, data: tempdata }) .then(() => {}) .catch(() => {}); };
问题原因与修复方案
1. 缺少匹配的Content-Type请求头
生成预签名URL时明确指定了ContentType: "application/pdf",但axios请求未携带该请求头。S3验证签名时会将请求头纳入计算,Postman会自动根据文件类型添加正确的Content-Type,所以能成功上传,而React请求因头不匹配导致签名验证失败。
修复:在axios请求中添加headers字段,指定与预签名URL一致的Content-Type:
const onFileUploadChange = async (e) => { const file = e.target.files[0]; return axios({ method: 'put', url: presigned_url_link, data: file, // 直接传入File对象,无需转换 headers: { 'Content-Type': file.type // 或固定写"application/pdf",file.type更适配不同文件类型 } }) .then(() => {}) .catch(() => {}); };
2. 冗余的ArrayBuffer转换
原代码中用FileReader将文件转为ArrayBuffer是不必要的,axios可以直接接收File对象作为请求体,转换操作反而可能导致签名计算的内容与预签名时的预期不一致。去掉转换后不仅简化代码,还能避免潜在的签名问题。
额外排查点
- 确认预签名URL生成时的
Key参数与实际上传的对象键完全一致,无拼写错误或路径差异 - 检查Lambda执行角色的IAM权限是否包含
s3:PutObject操作 - 确保上传操作在预签名URL的有效期内完成(当前设置为5分钟)
内容的提问来源于stack exchange,提问作者Sharath
相关产品推荐
相关产品推荐

