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

FastAPI/Unvicorn中间件调用call_next时请求无规律挂起问题咨询

问题1答复

不能直接判定问题出自FastAPI而非Uvicorn/其他组件。
你观察到的call_next阶段挂起、路径操作函数首条日志未输出的现象,本质是await call_next(request)执行时,Starlette(FastAPI底层依赖的Web框架)需要先完成请求体全量读取、参数解析校验、路由匹配全流程,才会进入你定义的路径函数。这一阶段的链路涉及Uvicorn的请求IO处理、Starlette的Multipart表单解析逻辑、甚至上游Cortex网关的请求转发逻辑,任意环节出问题都会导致该阶段挂起。

问题2答复

可能的故障原因

  • 上游请求传输不完整:Cortex.dev网关或客户端出现半开连接,请求头已经送达服务端(所以中间件pre请求日志正常打印),但请求体(尤其是你上传的图片数据)未完整传输,服务端一直在等待请求体数据,导致解析流程卡住。
  • 旧版本依赖的已知bug:你当前使用的FastAPI/Starlette/Uvicorn版本存在Multipart表单/文件上传解析的已知bug,触发特定条件时会出现无限挂起。
  • 事件循环被意外阻塞:如果在请求解析的依赖链中存在未异步化的同步阻塞IO操作(比如隐藏的同步文件读取、网络调用),会直接卡住整个async事件循环,导致所有该worker上的请求都无法继续处理。
  • 大文件上传无超时:如果上传的图片体积过大,且没有配置请求体读取超时,会导致服务端长时间等待数据传输完成,表现为无规律挂起。

修复方案

  1. 先加请求监控定位问题:在中间件pre逻辑中新增Content-Length请求头打印,对比正常请求和挂起请求的请求头差异,同时用tcpdump抓包确认挂起时请求体是否完整送达服务端,排除Cortex网关/客户端的传输问题。
  2. 升级核心依赖版本:将FastAPI、Starlette、Uvicorn全部升级到最新稳定版,规避已知的解析逻辑bug。
  3. 手动加请求读取超时:不使用FastAPI默认的UploadFile+Form参数自动解析,改为在路径函数中手动读取请求体,并用asyncio.wait_for包裹读取逻辑,设置合理的超时时间(比如30秒),超时后直接抛出异常避免无限挂起,示例逻辑如下:
import asyncio
@app.post("/")
async def run(request: Request):
    try:
        cortexId = request.headers.get('x-request-id')
        print("Cortex ID: " + cortexId +  " >>> 开始读取请求. Time stamp: " + str(datetime.now()))
        # 30秒超时读取表单内容
        form = await asyncio.wait_for(request.form(), timeout=30)
        image = form.get("image")
        renderFactor = int(form.get("renderFactor", 12))
        requestId = form.get("requestId", "-1")
        include_header = form.get("include_header", "bin")
        # 后续原有逻辑
    except asyncio.TimeoutError:
        raise HTTPException(status_code=408, detail="请求读取超时")
  1. 避免事件循环阻塞:所有同步阻塞操作(哪怕是第三方库的调用)都不要直接在async函数中执行,用asyncio.to_thread包裹扔到线程池运行,或者改成def类型的同步路径函数,FastAPI会自动把同步路径函数扔到线程池执行,不会阻塞事件循环。

内容的提问来源于stack exchange,提问作者Crashalot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 20:24:04