flask/fastapi接收图片流需前端用formdata并匹配字段名,flask用request.files.get('image')后.read()或.save(),fastapi需file(...)参数并await read();保存时须截取文件名、校验扩展名、uuid重命名、配置上传路径、避免web根目录及权限风险。

Flask/FastAPI 怎么接收 request.files 里的二进制图片流
后端收不到图片,八成是前端没发对、后端没读对。不是所有框架都默认解析 multipart/form-data,比如 FastAPI 默认不自动处理 request.files(它压根没这个属性),而 Flask 的 request.files 只在 Content-Type 正确且表单字段名匹配时才可用。
实操建议:
- 前端必须用
FormData构造请求,append('image', fileInput.files[0])—— 字段名(这里是image)要和后端取的 key 一致 - Flask 中用
request.files.get('image'),别直接用request.files['image'],否则文件缺失会 500;拿到对象后调用.read()或.save()才真正读取流 - FastAPI 必须显式声明参数为
File(...),例如def upload(image: UploadFile = File(...));UploadFile.file是个类似BytesIO的流,需用await image.read()(异步)或image.file.read()(同步模式下)获取 bytes - 别在内存里长期 hold 大图——超过几 MB 就该边读边写磁盘,否则容易 OOM
保存路径怎么避开 ../ 路径遍历和硬编码风险
用户传个文件名 ../../etc/passwd,你直接拼到 os.path.join(UPLOAD_DIR, filename),就等于把系统文件给覆盖了。硬编码路径(如 /var/www/uploads)还会导致本地开发和部署环境不一致。
实操建议:
- 永远用
os.path.basename(filename)截掉路径部分,只留原始文件名;如果需要保留扩展名,再额外校验filename.rsplit('.', 1)[-1].lower() in {'png', 'jpg', 'jpeg', 'webp'} - 生成存储路径时,别拼用户输入:用
uuid4().hex + '.' + ext重命名,上传目录用配置项(如app.config['UPLOAD_FOLDER'])而非字符串字面量 - 确保上传目录不在 Web 根目录下——比如 Nginx 配置了
location /static/指向/opt/app/static,那你的UPLOAD_FOLDER就不该设成/opt/app/static/uploads,否则用户可能通过 URL 直接访问未审核图片 - Linux 下注意目录权限:运行 Web 进程的用户(如
www-data)必须对上传目录有写权限,但不能有执行权限(chmod 755即可,别777)
file.save() 和手动 open(..., 'wb') 有什么区别
Flask 的 FileStorage.save() 看似方便,但它内部就是帮你做了 open(..., 'wb') + shutil.copyfileobj(),没有额外安全机制。反而因为封装了一层,容易让人忽略临时文件残留、大文件阻塞等问题。
实操建议:
-
file.save(path)适合小图( - 手动写要用
with open(path, 'wb') as f:,别忘了f.flush()和os.fsync(f.fileno())(尤其在 NFS 或低配云盘上,避免缓存丢失) - 如果图片要缩放/转格式,别先 save 再打开处理——应该从
file.read()拿 bytes 后用PIL.Image.open(BytesIO(data))直接操作,处理完再一次性写入磁盘,减少 IO 次数 - 注意
file.save()不校验文件内容,传个.exe改名成.jpg它也照存不误,所以重命名+后缀白名单必须前置
为什么上传后图片打不开?常见错误现象和排查点
最典型的是“图片已损坏”或“无法解析格式”,往往不是代码逻辑错,而是流没读全、编码混淆、或 MIME 类型误判。
实操建议:
- 检查是否重复读流:
file.read()一次后,流指针到底了,再调一次返回空 bytes;FastAPI 的UploadFile也是单次读取,别反复await image.read() - 别用
str(file.read())或.decode('utf-8')处理图片 bytes——二进制数据不是文本,强转会破坏内容 - 上传后立刻用
python -m PIL.Image xxx.jpg验证能否被 Pillow 正确加载;如果失败,用filetype.guess(data)检查实际类型,比后缀更可靠 - 如果走 CDN 或代理(如 Nginx),确认它们没截断大请求:
client_max_body_size(Nginx)、max_content_length(Flask)都要设够,比如16m
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











