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
相关产品推荐
相关产品推荐

