AWS S3预签名URL上传异常:生成URL无法打开求排查
我后端实现了AWS S3的文件上传、下载功能,下载正常,但上传用的预签名URL生成后无法打开,也没法从本地上传文件,调整过Content-Type和Key参数还是没解决。针对这个问题,整理以下排查和解决要点:
确认预签名URL的生成逻辑
上传预签名必须用putObject操作(对应HTTP PUT请求),要是误用getObject生成URL,就会导致上传失败。举个AWS SDK Python的例子:# 错误:用get_object生成上传URL,只能用于下载 s3.generate_presigned_url('get_object', Params={'Bucket': 'my-bucket', 'Key': 'test.txt'}) # 正确:用put_object生成上传URL,指定必要参数 s3.generate_presigned_url('put_object', Params={'Bucket': 'my-bucket', 'Key': 'test.txt', 'ContentType': 'text/plain'}, ExpiresIn=3600)另外,直接在浏览器打开这个URL(默认GET请求)肯定会报错,必须用PUT请求来上传文件。
严格匹配Content-Type
生成预签名时指定的Content-Type,必须和实际上传请求的Content-Type完全一致——大小写、附加参数都不能错。比如生成时设的是image/png,上传时就不能传image/jpeg;要是生成时没指定这个参数,上传请求里也不能加Content-Type请求头,否则签名校验不通过。检查S3桶的CORS配置
如果是浏览器端上传,桶的CORS规则必须允许PUT请求、对应的源域名和请求头。示例配置:<?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> <CORSRule> <AllowedOrigin>https://your-frontend-domain.com</AllowedOrigin> <!-- 生产环境别用* --> <AllowedMethod>PUT</AllowedMethod> <AllowedHeader>Content-Type</AllowedHeader> <MaxAgeSeconds>3000</MaxAgeSeconds> </CORSRule> </CORSConfiguration>验证IAM权限和URL有效期
生成预签名的IAM实体(用户/角色)必须有s3:PutObject权限,策略示例:{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::my-bucket/*" } ] }同时检查
ExpiresIn参数,别设置得太短导致URL很快过期。排查Key的编码问题
如果文件名(Key)包含空格、中文、特殊符号,要确保SDK自动做了URL编码,或者手动正确编码。比如我的文件.pdf要转成%E6%88%91%E7%9A%84%E6%96%87%E4%BB%B6.pdf,否则URL会解析出错。用curl测试排除前端问题
直接用curl命令测试预签名URL,确认是否是前端请求的问题:# 替换成你的预签名URL和本地文件 curl -X PUT -T "本地文件.txt" "你的预签名URL" -H "Content-Type: text/plain"如果curl能成功上传,那问题就出在前端的请求方式或请求头设置上。
内容的提问来源于stack exchange,提问作者Punam

