使用Boto3生成的S3预签名URL未包含指定区域,请求返回IllegalLocationConstraintException错误
看起来你遇到的问题核心是me-south-1这类区域的S3需要显式指定区域专属的endpoint,默认情况下Boto3没有正确使用该endpoint生成预签名URL,导致URL缺少区域信息、签名不匹配,最终触发IllegalLocationConstraintException错误。
具体解决方案
给S3客户端添加显式的区域endpoint
初始化S3客户端时,额外指定endpoint_url参数,明确指向me-south-1区域的S3专属地址:REGION_NAME = 'me-south-1' # 初始化带显式区域endpoint的S3客户端 s3_client = boto3.client( "s3", aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key=AWS_SECRET_KEY, region_name=REGION_NAME, endpoint_url=f"https://s3.{REGION_NAME}.amazonaws.com" )重新生成预签名URL
修改客户端配置后,调用create_presigned_url_expanded生成的URL会自动包含区域信息(格式类似https://{AWS_BUCKET_NAME}.s3.me-south-1.amazonaws.com/kyc/xxx),且签名是基于正确的endpoint生成的,不会出现手动修改URL后的签名验证失败问题。
问题原因解析
S3的部分区域(包括me-south-1)属于区域特定endpoint,不支持全局的s3.amazonaws.com地址。如果没有显式指定区域endpoint,Boto3会默认使用全局endpoint生成预签名URL,而你的桶实际在me-south-1区域,当请求全局endpoint时,AWS会检测到桶的区域不匹配,返回IllegalLocationConstraintException错误。
你之前手动给URL加区域无效,是因为预签名URL的签名和生成时使用的endpoint强绑定,手动修改URL会破坏签名的有效性,必须让Boto3用正确的endpoint生成完整的URL。
额外验证建议
可以用AWS CLI确认桶的区域是否确实为me-south-1:
aws s3api get-bucket-location --bucket {AWS_BUCKET_NAME}
返回的LocationConstraint应该是me-south-1,确保和你配置的区域一致。
备注:内容来源于stack exchange,提问作者Mohsen Bizhani

