Django部署至Vercel后无法向AWS S3上传图片问题排查
问题描述
基于Django开发的网站,本地环境可正常上传、查看AWS S3中的媒体图片,但部署到线上(https://django-images-practice.vercel.app/)后,仅能查看S3图片,无法上传新图片,上传时触发以下错误:
ClientError at / An error occurred (400) when calling the HeadObject operation: Bad Request
错误指向代码中的form_instance.save()行。
相关代码如下:
views.py
def make_and_see(request): if request.method == 'POST': form_instance = ProductForm(request.POST, request.FILES) if form_instance.is_valid(): form_instance.save() messages.success(request, 'Picture is saved') return redirect('home') else: messages.error(request, form_instance.errors) return redirect('home') else: context = {'data': Product.objects.all().order_by('?').first(), 'my_form': ProductForm(), 'time': timezone.now} return render(request, 'app1/home.html', context)
settings.py
STORAGES = {"default": {"BACKEND": "storages.backends.s3boto3.S3Boto3Storage"}, "staticfiles": {"BACKEND": "storages.backends.s3boto3.S3StaticStorage"}} AWS_ACCESS_KEY_ID = os.environ["MY_AWS_ACCESS_KEY_ID"] AWS_SECRET_ACCESS_KEY = os.environ["MY_AWS_SECRET_ACCESS_KEY"] AWS_STORAGE_BUCKET_NAME = '****' AWS_S3_REGION_NAME = 'ap-south-1' AWS_QUERYSTRING_AUTH = False AWS_DEFAULT_ACL = None AWS_S3_FILE_OVERWRITE = False AWS_S3_CUSTOM_DOMAIN = f"{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com"
部署环境:网站托管在Vercel,PostgreSQL数据库托管在Railway,已尝试添加AWS_S3_REGION_NAME配置但问题未解决。
排查建议
- 验证Vercel环境变量配置:确认Vercel后台的
MY_AWS_ACCESS_KEY_ID和MY_AWS_SECRET_ACCESS_KEY环境变量是否完全正确,无拼写错误、多余空格或未同步的情况。本地正常运行说明密钥本身有效,但线上可能存在变量配置疏漏。 - 检查IAM用户权限:确保对应AWS密钥的IAM用户拥有S3的
PutObject、HeadObject等核心操作权限,可临时附加AmazonS3FullAccess权限做测试(测试后再细化权限),排除权限不足导致的400错误。 - 手动指定S3端点:针对ap-south-1区域,在
settings.py中添加端点配置:
部分区域的默认端点可能存在解析问题,手动指定可避免区域不匹配触发的错误。AWS_S3_ENDPOINT_URL = "https://s3.ap-south-1.amazonaws.com" - 调整Vercel上传大小限制:Vercel默认文件上传大小限制为4MB,若上传图片超出该限制会触发请求错误。在项目根目录创建
vercel.json并配置:
上述配置将最大请求体大小设为10MB,可根据实际需求调整。{ "functions": { "api/*.py": { "maxRequestBodySize": 10485760 } } } - 添加错误日志调试:在
views.py中捕获ClientError并打印详细错误信息,便于定位问题:
通过Vercel日志功能查看具体错误详情,能更精准排查问题。from botocore.exceptions import ClientError import logging def make_and_see(request): if request.method == 'POST': form_instance = ProductForm(request.POST, request.FILES) if form_instance.is_valid(): try: form_instance.save() messages.success(request, 'Picture is saved') return redirect('home') except ClientError as e: logging.error(f"S3 Error Details: {e.response['Error']}") messages.error(request, f"Upload failed: {e.response['Error']['Message']}") return redirect('home') else: messages.error(request, form_instance.errors) return redirect('home') # 其余代码不变 - 确认存储桶名称正确性:检查
AWS_STORAGE_BUCKET_NAME中的桶名是否完全匹配线上配置,避免因桶名拼写错误导致请求到不存在的存储桶触发400错误。
内容的提问来源于stack exchange,提问作者Prashant Das
相关产品推荐
相关产品推荐

