You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:12:47