如何在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
相关产品推荐
相关产品推荐

