AWS S3 POST Policy精确文件大小验证失效问题求助
问题描述
我希望为预签名URL添加文件大小验证,确保客户端上传的文件大小与签名时指定的完全一致。但当我设置如下条件时:
"conditions": [ {"acl": "public-read"}, .... , ["content-length-range", 1024, 1024] ]
小文件可以正常验证,但较大的文件(例如25MB)会返回EntityTooSmall错误。只有将最小值设为0时验证才生效:
["content-length-range", 0, 1024]
我需要强制执行精确文件大小而非范围,请问S3是否不支持精确文件大小匹配?
**编辑:**以下是我编写的完整Python代码:
# Create an S3 client s3 = boto3.client( 's3', aws_access_key_id="...", aws_secret_access_key="...", region_name="sfo3", endpoint_url="https://sfo3.digitaloceanspaces.com", ) # Specify the bucket name bucket_name = 'my_bucket' # Specify the file name file_name = 'SampleJPGImage_30mbmb.jpeg' # Get the file size in bytes file_size = os.path.getsize(file_name) # Use the file size and content print("File size:", file_size, "bytes") # Should be 30789588 # Specify the desired file size in bytes file_size_min = file_size file_size_max = file_size # Sign the policy with your AWS secret key signedPolicy = s3.generate_presigned_post( Bucket=bucket_name, Key=file_name, Fields={ "acl": "public-read", "key": file_name, }, Conditions=[ {"acl": "public-read"}, {"key": file_name}, ["content-length-range", file_size_min, file_size_max] ], ExpiresIn=3600 ) # Use the signed policy to upload the file with open(file_name, 'rb') as f: print() resp = requests.post(signedPolicy['url'], data=signedPolicy['fields'], files={'file': f}) print(resp) print(resp.content)
解决方案
S3(以及兼容S3的存储服务如DigitalOcean Spaces)支持通过content-length-range设置精确文件大小匹配,大文件上传时出现EntityTooSmall错误的核心原因是:使用requests.post的files参数上传大文件时,requests会自动启用分块编码(chunked encoding),导致请求中缺失Content-Length头,而S3的预签名策略验证依赖该头匹配content-length-range条件,从而触发大小不匹配错误。
具体解决步骤:
强制请求携带
Content-Length头并禁用分块编码
修改上传代码,手动指定文件大小作为请求头,同时启用stream=True避免自动分块:with open(file_name, 'rb') as f: # 手动设置Content-Length头 headers = {'Content-Length': str(file_size)} resp = requests.post( signedPolicy['url'], data=signedPolicy['fields'], files={'file': f}, headers=headers, stream=True ) print(resp) print(resp.content)小文件上传时requests默认不使用分块编码,
Content-Length头正常传递,因此精确验证生效;大文件需手动干预确保头信息正确发送。上传后二次验证(备选方案)
如果无法通过请求头解决,可在上传完成后调用S3 API获取文件实际大小,与预期值对比,不匹配则删除文件:# 上传完成后验证大小 resp = s3.head_object(Bucket=bucket_name, Key=file_name) actual_size = resp['ContentLength'] if actual_size != file_size: s3.delete_object(Bucket=bucket_name, Key=file_name) # 此处可添加错误通知或业务逻辑处理
内容的提问来源于stack exchange,提问作者BVtp
相关产品推荐
相关产品推荐

