Amazon S3预签名URL PUT上传报SignatureDoesNotMatch,StringToSign显示GET
问题根因
你遇到的SignatureDoesNotMatch错误核心是预签名URL生成时使用的HTTP方法和实际请求方法不匹配。
S3生成预签名URL的过程中,会将HTTP方法作为必选参数纳入签名计算,生成时用什么方法,实际请求时必须严格使用相同方法。你返回的错误信息里StringToSign字段明确标记为GET,说明你当前前端使用的这个预签名URL,生成时指定的就是GET方法(比如调用AWS SDK时错误使用了getObject操作而非putObject),不管你前端用fetch发什么类型的请求,S3签名校验都会按照生成时的GET方法计算,自然会匹配失败。
你用curl可以正常上传的原因,大概率是测试curl时使用的是另一个正确生成的PUT类型预签名URL,和前端fetch用的不是同一个。
修复步骤
- 首先修正预签名URL的生成逻辑,明确指定生成PUT类型的预签名URL,以Node.js AWS SDK为例:
// 错误写法:生成的是GET类型的预签名URL const wrongUrl = s3.getSignedUrl('getObject', { Bucket: '你的bucket名', Key: 'copy.mp3', Expires: 3600 }) // 正确写法:生成的是PUT类型的预签名URL const correctUrl = s3.getSignedUrl('putObject', { Bucket: '你的bucket名', Key: 'copy.mp3', Expires: 3600, ContentType: 'audio/mpeg' // 这里指定的ContentType必须和前端请求时传的完全一致 })
- 修正你的fetch请求,补充要上传的文件作为请求体:
// 假设你要上传的文件存在file变量里,比如从input[type=file]获取的File对象 fetch("你的PUT类型预签名URL", { method: "PUT", headers: { "content-type": "audio/mpeg" // 必须和生成预签名URL时指定的ContentType完全一致 }, body: file, // 这里必须传入要上传的文件内容 mode: "cors", credentials: "omit" });
- 检查S3桶的CORS配置,确保允许你的站点(比如
http://localhost:3000)发送PUT请求,允许content-type头:
<CORSConfiguration> <CORSRule> <AllowedOrigin>http://localhost:3000</AllowedOrigin> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>Content-Type</AllowedHeader> </CORSRule> </CORSConfiguration>
内容的提问来源于stack exchange,提问作者Edw
相关产品推荐
相关产品推荐

