You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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条件,从而触发大小不匹配错误。

具体解决步骤:

  1. 强制请求携带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头正常传递,因此精确验证生效;大文件需手动干预确保头信息正确发送。

  2. 上传后二次验证(备选方案)
    如果无法通过请求头解决,可在上传完成后调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 01:15:31