如何使用Python向Amazon S3预签名URL上传文件
S3预签名URL上传问题解答
核心结论
- 你当前生成的是
get_object操作类型的预签名URL,仅支持S3对象下载,无法直接用于上传文件 - 要通过预签名URL实现上传,需要先生成
put_object操作类型的专用预签名URL,再通过HTTP PUT请求提交文件即可
具体实现步骤
步骤1:生成上传专用预签名URL
修改原有生成逻辑,将客户端操作类型从get_object替换为put_object即可:
import logging import boto3 from botocore.exceptions import ClientError def create_presigned_upload_url(bucket_name, object_name, expiration=3600): """生成用于S3对象上传的预签名URL :param bucket_name: S3桶名称 :param object_name: 上传后在S3存储中的对象键(文件路径/名称) :param expiration: URL有效期,单位为秒,默认1小时 :return: 预签名URL字符串,生成失败返回None """ s3_client = boto3.client('s3') try: response = s3_client.generate_presigned_url( ClientMethod='put_object', Params={'Bucket': bucket_name, 'Key': object_name}, ExpiresIn=expiration ) except ClientError as e: logging.error(e) return None return response # 调用示例:生成上传到bucket123、对象键为upload_test.txt的预签名URL upload_url = create_presigned_upload_url("bucket123", "upload_test.txt")
步骤2:使用预签名URL上传本地文件
可以借助requests库发起PUT请求完成上传,如未安装依赖可先执行pip install requests:
import requests import logging def upload_file_with_presigned_url(presigned_url, local_file_path): """通过预签名URL上传本地文件 :param presigned_url: 步骤1生成的上传专用预签名URL :param local_file_path: 本地待上传文件的完整路径 :return: 上传成功返回True,失败返回False """ try: with open(local_file_path, 'rb') as file: response = requests.put(presigned_url, data=file) # 状态码为200代表上传成功 response.raise_for_status() return True except Exception as e: logging.error(f"上传失败: {str(e)}") return False # 调用示例:上传本地路径下的local_test.txt文件 upload_status = upload_file_with_presigned_url(upload_url, "./local_test.txt")
注意事项
- 生成预签名URL的身份凭证必须拥有对应S3桶的
s3:PutObject权限,否则上传时会返回403错误 - 上传请求必须使用PUT方法,使用POST/GET方法都会触发签名校验失败
- 预签名URL过期后无法继续使用,需要重新生成
- 如果上传时需要指定
Content-Type等头参数,生成预签名URL时也需要在Params中传入对应参数,否则会出现签名不匹配错误。例如需要指定上传文本文件时,生成URL的Params需要改为{'Bucket': bucket_name, 'Key': object_name, 'ContentType': 'text/plain'},同时上传请求也要带上对应的Content-Type: text/plain请求头。
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

