上传至AWS S3的文件大小为0B的原因排查求助
问题原因与解决方案
核心问题分析
你遇到的0B文件上传问题,本质是两个关键错误导致:
- 文件指针耗尽:Flask的
FileStorage是类文件对象,当你在save_picture中调用Image.open(form_picture)时,已经将文件指针读取到了末尾。后续调用s3.upload_fileobj(file)时,从当前指针位置开始读取,自然获取不到任何内容,因此上传的文件大小为0B。 - 未上传处理后的图片:当前代码上传的是前端传来的原始文件,而非
save_picture中调整尺寸后的图片,完全不符合你的需求。
解决方案
修改代码逻辑,将处理后的图片保存到内存对象中,再上传至S3:
1. 导入必要模块
from io import BytesIO
2. 修改save_picture函数
让函数返回处理后的图片内存流和生成的文件名:
def save_picture(object_id, form_picture, path): if form_picture is None: return None, None random_hex = token_hex(8) filename = form_picture.filename if '.' not in filename: return None, None extension = filename.rsplit('.', 1)[1].lower() if not allowed_file(extension, form_picture): return None, None picture_fn = f'{object_id}_{random_hex}.{extension}' # 调整图片尺寸 output_size = (1280, 720) i = Image.open(form_picture) i.thumbnail(output_size) # 将处理后的图片写入内存BytesIO对象 img_bytes = BytesIO() # 根据图片扩展名选择对应保存格式(JPG需用'JPEG'格式) save_format = 'JPEG' if extension in ['jpg', 'jpeg'] else extension.upper() i.save(img_bytes, format=save_format) # 重置内存流指针到起始位置,方便后续读取上传 img_bytes.seek(0) return picture_fn, img_bytes
3. 修改上传逻辑
使用处理后的内存流上传至S3:
image_name, processed_image = save_picture(object_id=new_object.id, form_picture=file, path=f'{object_type}_images') if not image_name or not processed_image: return make_response({'msg': 'Invalid image file.'}, 400) s3 = boto3.client( 's3', aws_access_key_id=current_app.config['AWS_ACCESS_KEY'], aws_secret_access_key=current_app.config['AWS_SECRET_ACCESS_KEY'] ) try: s3.upload_fileobj( processed_image, current_app.config['AWS_BUCKET_NAME'], image_name, ExtraArgs={ 'ContentType': file.content_type } ) except Exception as e: print(e) return make_response({'msg': 'Something went wrong.'}, 500)
补充说明
如果你的需求是上传原始文件而非处理后的图片,仅需在上传前重置文件指针即可:
# 在调用save_picture后、上传前添加 file.seek(0) s3.upload_fileobj(...)
内容的提问来源于stack exchange,提问作者mikeCrafted
相关产品推荐
相关产品推荐

