如何在Fastapi中统一处理各种异常

496 阅读2分钟

在 FastAPI 中处理参数校验错误(通常由 Pydantic 模型或路径参数校验触发)需要使用自定义异常处理器捕获 RequestValidationError。以下是详细实现步骤:

1. 基础实现(返回标准错误结构)

from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

app = FastAPI()

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={
            "code": 422,
            "message": "参数校验失败",
            "errors": exc.errors()
        },
    )

# 示例路由
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str):
    return {"item_id": item_id, "q": q}

2. 自定义错误格式(简化输出)

@app.exception_handler(RequestValidationError)
async def custom_validation_handler(request: Request, exc: RequestValidationError):
    simplified_errors = []
    for error in exc.errors():
        # 提取关键信息
        simplified_errors.append({
            "field": "->".join(str(loc) for loc in error["loc"]),  # 错误字段路径
            "msg": error["msg"],
            "type": error["type"]
        })
    
    return JSONResponse(
        status_code=422,
        content={
            "error": "ValidationError",
            "detail": simplified_errors
        }
    )

3. 完整示例(含路由演示)

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(..., min_length=3)
    price: float = Field(gt=0)

@app.post("/items/")
async def create_item(item: Item):
    return item

# 测试无效请求
# curl -X POST 'http://localhost:8000/items/' \
# -H 'Content-Type: application/json' \
# -d '{"name": "AB", "price": -1}'

4. 处理自定义错误类型(扩展)

如果需要统一处理其他错误:

from fastapi import HTTPException

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={"error": exc.detail}
    )

关键说明:

  1. 错误信息结构

    {
      "loc": ["body", "price"],
      "msg": "ensure this value is greater than 0",
      "type": "value_error.number.not_gt"
    }
    
    • loc:错误位置(body/query/path/header等 + 字段路径)
    • msg:人类可读错误描述
    • type:错误类型标识符
  2. HTTP 状态码

    • 参数校验错误通常返回 422 Unprocessable Entity
    • 路径参数错误(如 item_id: int 接收到字符串)会触发相同错误
  3. 调试信息: 生产环境中建议隐藏详细错误,可通过环境变量控制:

    import os
    
    @app.exception_handler(RequestValidationError)
    async def handler(...):
        if os.getenv("ENV") == "prod":
            return JSONResponse(status_code=422, content={"error": "Invalid params"})
        else:
            # 返回完整错误
    

测试验证:

使用无效参数请求示例路由,将得到类似响应:

{
  "code": 422,
  "message": "参数校验失败",
  "errors": [
    {
      "field": "body->name",
      "msg": "ensure this value has at least 3 characters",
      "type": "value_error.any_str.min_length"
    },
    {
      "field": "body->price",
      "msg": "ensure this value is greater than 0",
      "type": "value_error.number.not_gt"
    }
  ]
}

提示:FastAPI 自动生成的文档(Swagger UI)中的参数校验错误由内置处理器处理,自定义处理器不影响文档界面行为。