FastAPI多文件上传时触发receive_nowait抛出WouldBlock错误求助
问题分析与解决方案
核心问题
你的异步接口中使用了同步IO操作(比如file.file.read()、open()/write()),这会阻塞FastAPI的异步事件循环,触发AnyIO的WouldBlock错误——异步环境下不允许同步阻塞调用占用事件循环线程。
另外还有两个潜在问题:
content: list = []的默认参数写法会导致多次请求共享同一个列表实例,引发数据混乱- 直接使用
file.filename作为保存路径可能存在安全风险(比如路径遍历攻击)
修复步骤
1. 安装异步文件操作依赖
先安装aiofiles库,用于异步读写文件:
pip install aiofiles
2. 修改接口代码
替换同步IO操作为异步版本,同时修复默认参数问题:
from typing import Optional, List from fastapi import FastAPI, File, UploadFile, Depends, HTTPException from sqlalchemy.orm import Session import aiofiles async def createNewDirectory( files: Optional[List[UploadFile]] = File(None), content: list = Depends(lambda: []), # 修复默认参数共享问题 db: Session = Depends(get_db) ): if not files: return {"message": "No files uploaded"} print(content) for file in files: try: # 用UploadFile的异步read方法替代同步的file.file.read() contents = await file.read() # 用aiofiles异步写入文件,避免阻塞事件循环 async with aiofiles.open(file.filename, 'wb') as f: await f.write(contents) except Exception as e: raise HTTPException(status_code=500, detail=f"Upload error: {str(e)}") finally: await file.close() # UploadFile的close是异步方法,需加await return {"message": "All files uploaded successfully"}
3. 额外优化建议
- 安全处理文件名:不要直接使用用户上传的
filename,可以生成随机文件名或拼接固定安全路径,防止路径遍历攻击 - 限制文件大小:在
File()中添加File(..., max_length=10*1024*1024)来限制单文件大小,避免内存溢出 - 细化异常处理:区分磁盘满、权限不足等不同异常类型,返回更精准的错误信息
错误原因说明
FastAPI基于Starlette和AnyIO实现异步架构,事件循环线程需要保持非阻塞状态。同步IO操作会占用线程直到操作完成,导致AnyIO无法处理其他请求,最终抛出WouldBlock异常——这是异步框架对阻塞操作的保护机制。
内容的提问来源于stack exchange,提问作者Deep Kumar Singh
相关产品推荐
相关产品推荐

