使用预签名URL上传至Glacier Instant Retrieval时标签丢失问题
问题原因
使用generate_presigned_url生成PUT对象的预签名URL时,Params中的Tagging参数不会自动纳入签名有效范围,也不会被转换为S3 PUT请求所需的查询参数或请求头。S3要求上传时的标签必须以**查询参数(tagging)或请求头(x-amz-tagging)**形式传递,且这些参数必须在预签名阶段被明确指定,否则上传时S3会忽略未签名的标签信息,导致标签缺失。
而直接调用put_object方法时,boto3会自动处理参数映射,将Tagging转换为符合S3 API要求的请求格式,因此标签能正常生效。
解决方法
有两种可行的处理方式:
方式一:将标签作为查询参数包含在预签名URL中
生成预签名URL时,对标签字符串进行URL编码后纳入Params,boto3会将其添加到URL查询字符串中,签名会包含该参数,上传时无需额外操作:
import boto3 import requests from urllib.parse import quote_plus # 对标签字符串进行URL编码,避免特殊字符解析错误 tagging_str = quote_plus("key1=value1&key2=value2") s3_client = boto3.client( "s3", region_name=AWS_REGION, aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, ) url = s3_client.generate_presigned_url( "put_object", Params=dict( Bucket=MY_BUCKET, Key=key, StorageClass="GLACIER_IR", Tagging=tagging_str ), ExpiresIn=EXPIRATION, ) with open(file_path, "rb") as file: response = requests.put(url, data=file)
方式二:通过请求头传递标签(需预签名时指定头)
生成预签名URL时,通过Headers参数指定x-amz-tagging,上传时在请求中携带对应请求头:
import boto3 import requests from urllib.parse import quote_plus tagging_str = quote_plus("key1=value1&key2=value2") s3_client = boto3.client( "s3", region_name=AWS_REGION, aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY, ) url = s3_client.generate_presigned_url( "put_object", Params=dict( Bucket=MY_BUCKET, Key=key, StorageClass="GLACIER_IR" ), Headers={"x-amz-tagging": tagging_str}, ExpiresIn=EXPIRATION, ) with open(file_path, "rb") as file: response = requests.put(url, data=file, headers={"x-amz-tagging": tagging_str})
注意:两种方式都必须对标签字符串进行URL编码,避免特殊字符(如&、=、空格等)导致参数解析失败。
内容的提问来源于stack exchange,提问作者Netanel
相关产品推荐
相关产品推荐

