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

FastAPI子模块捕获异常时如何记录完整请求对象?

FastAPI底层异常处理后记录顶层请求的优化方案

场景复现

你的FastAPI端点代码:

@router.post("/my_test")
async def post_my_test(request: Request):
    a = do_stuff(request.var1)
    b = do_different_stuff(request.var2)
    return a + b

底层业务逻辑中,calc_it会捕获异常并返回回退值:

async def calc_it(m, n):
    try:
        return m/n
    except ZeroDivisionError:
        logging.exception("Error occurred")
        return -1

现有三种方案的痛点:

  • 方案1:逐层传递异常信息到顶层记录,代码冗余,破坏业务逻辑简洁性
  • 方案2:逐层传递请求对象,无关函数被迫接收参数,维护成本高
  • 方案3:常规中间件/异常处理器无法捕获已被底层处理的异常

优化方案

方案一:用ContextVars传递请求标记(轻量无侵入)

ContextVars是Python为异步/多线程场景设计的上下文变量,天然隔离不同请求的上下文,不会出现异步任务标记串用的问题。

  1. 定义标记变量
from contextvars import ContextVar

need_log_request = ContextVar("need_log_request", default=False)
  1. 底层异常处设置标记
async def calc_it(m, n):
    try:
        return m/n
    except ZeroDivisionError:
        logging.exception("Error occurred")
        # 标记当前请求需要记录
        need_log_request.set(True)
        return -1
  1. 顶层端点统一处理记录
@router.post("/my_test")
async def post_my_test(request: Request):
    a = await do_stuff(request.var1)
    b = await do_different_stuff(request.var2)
    
    # 检查标记并记录请求
    if need_log_request.get():
        logging.info(f"Request to /my_test: {await request.json()}")
        # 可选:重置标记,避免跨上下文污染(ContextVars默认隔离,可不加)
        need_log_request.set(False)
    
    return a + b

优势:无需传递请求对象,仅用布尔标记实现逻辑分离,代码无冗余。

方案二:用ContextVars传递请求对象(直接高效)

你担心传递大对象是反模式,但ContextVars存储的是对象引用,不会拷贝整个请求,性能开销可忽略;且FastAPI的Request对象本身就是请求上下文内的单例,传递引用完全合理。

  1. 定义请求上下文变量
from contextvars import ContextVar
from fastapi import Request

current_request = ContextVar("current_request")
  1. 中间件自动注入请求对象
@app.middleware("http")
async def set_current_request(request: Request, call_next):
    current_request.set(request)
    response = await call_next(request)
    return response
  1. 底层直接获取请求并记录
async def calc_it(m, n):
    try:
        return m/n
    except ZeroDivisionError:
        request = current_request.get()
        logging.exception(f"Error occurred with request: {await request.json()}")
        return -1

优势:业务代码完全无需处理请求传递,中间件自动完成注入,底层可随时获取完整请求信息。

总结

两种方案均能解决代码冗余问题:方案一更轻量,适合仅需标记触发顶层记录的场景;方案二更直接,适合底层需要直接使用请求信息的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 10:57:08