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

如何在FastAPI中记录Pydantic类型校验失败的服务端日志?

在FastAPI服务端记录Pydantic验证失败的422错误日志

问题场景

当FastAPI接收到不符合Pydantic模型定义的请求时,会返回422 Unprocessable Entity错误,但这类错误默认仅反馈给客户端,服务端不会自动记录相关日志。比如以下示例:

示例代码

from pydantic import BaseModel
from fastapi import FastAPI, status

app = FastAPI()

class StudentModel(BaseModel):
    id: int
    name: str
    surname: str
    
@app.post("/", status_code=status.HTTP_201_CREATED)
async def create_student(student: StudentModel):
    # 业务逻辑实现
    pass

错误请求

{
  "name": "John",
  "surname": "Smith"
}

此时服务端返回422错误,但无日志留存,我们需要在服务端捕获并记录这类错误的请求详情。

解决方案

方法1:自定义RequestValidationError异常处理器

FastAPI允许针对RequestValidationError(Pydantic验证失败触发的异常)编写自定义处理器,在其中添加日志记录逻辑:

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

# 配置日志输出级别和格式
logging.basicConfig(
    level=logging.ERROR,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

app = FastAPI()

class StudentModel(BaseModel):
    id: int
    name: str
    surname: str

@app.exception_handler(RequestValidationError)
async def validation_error_logger(request: Request, exc: RequestValidationError):
    # 记录错误详情:请求URL、原始请求体、验证错误信息
    logger.error(
        f"请求验证失败 | URL: {request.url} | 请求体: {await request.body().decode('utf-8')} | 错误详情: {exc.errors()}"
    )
    # 保留原有422响应结构,不影响客户端接收错误信息
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={"detail": exc.errors(), "body": exc.body}
    )

@app.post("/", status_code=status.HTTP_201_CREATED)
async def create_student(student: StudentModel):
    pass

方法2:使用全局中间件捕获异常

如果需要统一处理更多类型的请求异常,可通过Starlette中间件实现全局日志捕获:

from fastapi import FastAPI, status
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
import logging
from fastapi.exceptions import RequestValidationError

# 配置日志
logging.basicConfig(
    level=logging.ERROR,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

app = FastAPI()

class GlobalErrorLoggingMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            response = await call_next(request)
            return response
        except Exception as exc:
            # 仅针对RequestValidationError记录日志
            if isinstance(exc, RequestValidationError):
                logger.error(
                    f"请求验证失败 | URL: {request.url} | 请求体: {await request.body().decode('utf-8')} | 错误详情: {exc.errors()}"
                )
            # 重新抛出异常,让默认或自定义处理器处理响应
            raise exc

app.add_middleware(GlobalErrorLoggingMiddleware)

class StudentModel(BaseModel):
    id: int
    name: str
    surname: str

@app.post("/", status_code=status.HTTP_201_CREATED)
async def create_student(student: StudentModel):
    pass

注意事项

  • 两种方法都能完整记录错误请求的关键信息,便于排查问题
  • 异常处理器方式更精准针对Pydantic验证错误,逻辑更聚焦
  • 中间件方式适合全局统一日志管理,可扩展处理其他类型异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:35:15