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

FastAPI路由场景下自定义处理422/400/500异常及422处理失效问题

FastAPI自定义HTTP状态码422、400、500异常处理方案

一、修复422(RequestValidationError)自定义处理不生效的问题

你的代码存在重复注册异常处理器的冲突:同时使用了@app.exception_handler(RequestValidationError)装饰器和app.add_exception_handler(RequestValidationError, validation_exception_handler),这会导致逻辑混乱。只需要保留其中一种注册方式即可,以下是修正后的代码:

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from fastapi.routing import APIRouter
from pydantic import jsonable_encoder

router = APIRouter()

# 测试路由:触发请求体/参数校验失败的场景
@router.post("/test")
async def test_route(name: str, age: int):
    return {"name": name, "age": age}

app = FastAPI()

# 注册RequestValidationError(对应422状态码)的自定义处理器
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({
            "code": 422,
            "message": "请求参数校验失败",
            "error_details": exc.errors(),
            "request_body": exc.body
        }),
    )

# 挂载路由(位置不影响全局异常处理器生效)
app.include_router(router)

若仍不生效,排查以下点:

  • 确认请求确实触发了RequestValidationError:比如POST请求体格式错误、参数类型不匹配等
  • 检查路由内部是否自行捕获了异常并返回响应,这会跳过全局异常处理器

二、实现400(Bad Request)自定义异常处理

400状态码多用于客户端业务参数错误,可通过自定义异常类+全局处理器实现:

from fastapi import HTTPException

# 自定义400异常类(便于区分业务场景,也可直接用原生HTTPException)
class BadRequestException(HTTPException):
    def __init__(self, detail: str):
        super().__init__(status_code=status.HTTP_400_BAD_REQUEST, detail=detail)

# 注册400异常处理器
@app.exception_handler(BadRequestException)
async def bad_request_exception_handler(request: Request, exc: BadRequestException):
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=jsonable_encoder({
            "code": 400,
            "message": exc.detail
        }),
    )

# 路由中抛出异常示例
@router.post("/check-phone")
async def check_phone(phone: str):
    if not phone.startswith("1"):
        raise BadRequestException(detail="手机号格式错误,必须以1开头")
    return {"phone": phone}

如果要统一处理所有原生HTTPException中的400状态码,可做如下判断:

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    if exc.status_code == status.HTTP_400_BAD_REQUEST:
        return JSONResponse(
            status_code=400,
            content=jsonable_encoder({
                "code": 400,
                "message": exc.detail
            })
        )
    # 其他HTTP状态码保留默认处理逻辑
    return JSONResponse(
        status_code=exc.status_code,
        content=jsonable_encoder({"detail": exc.detail})
    )

三、实现500(Internal Server Error)自定义异常处理

500对应服务器内部错误,可通过捕获全局Exception实现统一处理:

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content=jsonable_encoder({
            "code": 500,
            "message": "服务器内部错误",
            # 生产环境建议隐藏具体错误信息,仅调试时开启
            "debug_info": str(exc) if app.debug else None
        }),
    )

注意:生产环境下不要返回具体异常信息,避免泄露服务器内部细节,仅保留通用提示即可。

四、关键注意事项

  • 异常处理器注册顺序:同一异常类型的处理器,最后注册的会覆盖之前的,避免重复注册
  • 路由挂载位置:全局异常处理器对整个应用生效,与include_router的顺序无关
  • 调试模式:开启app = FastAPI(debug=True)时,FastAPI会返回详细错误信息,生产环境建议关闭

内容的提问来源于stack exchange,提问作者Vinuta Basavaraj Hiremath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 13:07:37