如何避免boto3 put_object将S3桶名添加到文件路径中?
这个问题的核心是boto3对自定义S3端点的默认寻址方式,和你的生产环境S3实例、CLI工具的行为不一致。
boto3在处理非AWS官方S3端点时,默认可能采用path-style寻址(把桶名直接拼在URL路径里,也就是你日志里看到的/s3-bucket-337381/raw/xxx.xml格式),而你的生产环境S3兼容存储或者CLI工具默认用的是virtual-hosted寻址(桶名作为请求域名的一部分,比如https://s3-bucket-337381.your-s3-endpoint.com/raw/xxx.xml),这就导致了请求格式不匹配。
解决步骤
导入botocore配置类
在代码中添加Config类的导入:from botocore.config import Config修改S3客户端创建逻辑,指定寻址方式
在get_client函数中加入config参数,显式设置S3的寻址风格为virtual(或auto,让botocore自动适配):@cache def get_client() -> boto3.client: if cfg.get_item('s3', 'enable', False): params = dict() params['aws_access_key_id'] = cfg.get_item('s3', 'access_key_id') params['aws_secret_access_key'] = cfg.get_item('s3', 'secret_key') params['region_name'] = cfg.get_item('s3', 'region', 'eu-west-1') if cfg.get_item('s3', 'token', ''): params['aws_session_token'] = cfg.get_item('s3', 'token') params['endpoint_url'] = cfg.get_item('s3', 'url') # 显式设置寻址风格为virtual-hosted params['config'] = Config(s3={'addressing_style': 'virtual'}) return boto3.client('s3', **params) raise StorageError('S3 is not enabled, can not get a S3 client ready.')如果
virtual模式不适用(比如生产环境存储只支持path-style),可以尝试设置为auto,让botocore根据端点自动判断合适的寻址方式:params['config'] = Config(s3={'addressing_style': 'auto'})修复状态码判断错误
你的put_file函数中,return response['ResponseMetadata'] == 200是错误的——ResponseMetadata是一个字典,状态码存在HTTPStatusCode字段里,应该修改为:return response['ResponseMetadata']['HTTPStatusCode'] == 200
验证
修改后重新部署,检查请求的url_path是否不再包含桶名,而是将桶名放在请求的主机头或子域名中,和CLI的请求格式保持一致。
内容的提问来源于stack exchange,提问作者Alberto

