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

如何在Django应用中上传媒体文件到AWS S3并解决ACL不支持错误

Django管理面板上传S3图片报错:AccessControlListNotSupported

错误信息:

An error occurred (AccessControlListNotSupported) when calling the PutObject operation: The bucket does not allow ACLs

已按照django-storages文档配置settings.py与AWS环境,静态文件可正常读取,但媒体文件上传失败。尝试修改AWS_DEFAULT_ACL为'none'和'public-read-write'仍无效。

当前settings.py配置:

if USE_S3:
    # aws settings
    AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
    AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
    AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
    AWS_DEFAULT_ACL = public-read
    AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME')
    AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
    AWS_S3_OBJECT_PARAMETERS = {'CacheControl': 'max-age=86400'}
    #Additional settings
    AWS_S3_FILE_OVERWRITE = False
    AWS_QUERYSTRING_AUTH = False
    # s3 static settings
    AWS_STATIC_LOCATION = 'static'
    STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_STATIC_LOCATION}/'
    STATICFILES_STORAGE = 'myproject.storages.StaticStore'
    # s3 media settings
    AWS_MEDIA_LOCATION = 'media'
    MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_MEDIA_LOCATION}/'
    DEFAULT_FILE_STORAGE = 'myproject.storages.MediaStore'
else:
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')


STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

当前AWS Bucket Policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::my-bucket/*"
        },
        {
            "Sid": "Statement2",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::my-bucket/"
        }
    ]
}

解决方案

这个错误的核心原因是你的S3桶已经禁用了ACL功能,但django-storages上传文件时仍在发送ACL相关请求参数,导致冲突。按以下步骤修复:

  • 修改settings.py,彻底禁用ACL相关配置
    把AWS_DEFAULT_ACL设为Python的None(不是字符串'none'),新增AWS_S3_ACL_DISABLED = True强制不发送ACL请求头,同时在AWS_S3_OBJECT_PARAMETERS里明确设置ACL: None。修改后的配置段示例:

    if USE_S3:
        # aws settings
        AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
        AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
        AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
        AWS_DEFAULT_ACL = None  # 改为Python原生None
        AWS_S3_REGION_NAME = os.environ.get('AWS_S3_REGION_NAME')
        AWS_S3_CUSTOM_DOMAIN = f'{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com'
        AWS_S3_OBJECT_PARAMETERS = {
            'CacheControl': 'max-age=86400',
            'ACL': None  # 明确不传递ACL参数
        }
        #Additional settings
        AWS_S3_FILE_OVERWRITE = False
        AWS_QUERYSTRING_AUTH = False
        AWS_S3_ACL_DISABLED = True  # 关键:禁用所有ACL请求
        # s3 static settings
        AWS_STATIC_LOCATION = 'static'
        STATIC_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_STATIC_LOCATION}/'
        STATICFILES_STORAGE = 'myproject.storages.StaticStore'
        # s3 media settings
        AWS_MEDIA_LOCATION = 'media'
        MEDIA_URL = f'https://{AWS_S3_CUSTOM_DOMAIN}/{AWS_MEDIA_LOCATION}/'
        DEFAULT_FILE_STORAGE = 'myproject.storages.MediaStore'
    
  • 检查S3桶所有权设置
    确认桶的对象所有权设置为桶所有者强制(Bucket owner enforced),这是禁用ACL后的标准配置,文件权限将由桶的默认规则控制。你的Bucket Policy已经允许s3:*权限,这部分无需调整。

  • 验证自定义存储类
    如果你自己实现了StaticStore和MediaStore类,检查是否有硬编码设置ACL的代码,比如重写default_acl或get_object_parameters方法,若有则删除相关ACL配置。

内容的提问来源于stack exchange,提问作者mazmusa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:20:26