三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

FastAPI 错误处理

FastAPI 错误处理

FastAPI 错误处理学习笔记

一、HTTPException — 主动抛出错误

1. 基本用法

fromfastapiimportFastAPI,HTTPException app=FastAPI()items={"foo":"The Foo Wrestlers"}@app.get("/items/{item_id}")asyncdefread_item(item_id:str):ifitem_idnotinitems:raiseHTTPException(status_code=404,detail="Item not found")return{"item":items[item_id]}

关键点

  • HTTPException异常类,必须用raise抛出,不是return
  • FastAPI 捕获后会将其转换为 HTTP 响应,返回对应的 status_code 和 JSON body。
  • 返回格式:{"detail": "Item not found"}

2. 自定义 detail

detail可以是任何 JSON 可序列化的值:

raiseHTTPException(status_code=404,detail={"msg":"Item not found","item_id":item_id})

响应:

{"detail":{"msg":"Item not found","item_id":"bar"}}

3. 添加自定义响应头

raiseHTTPException(status_code=401,detail="Not authenticated",headers={"WWW-Authenticate":"Bearer"},)

典型场景:401 响应需要返回WWW-Authenticate头,告知客户端应使用何种认证方式。


二、自定义异常处理器

1. 注册异常处理器 —@app.exception_handler

fromfastapiimportFastAPI,Requestfromfastapi.responsesimportJSONResponseclassUnicornException(Exception):def__init__(self,name:str):self.name=name app=FastAPI()@app.exception_handler(UnicornException)asyncdefunicorn_exception_handler(request:Request,exc:UnicornException):returnJSONResponse(status_code=418,content={"message":f"Oops!{exc.name}did something."},)@app.get("/unicorns/{name}")asyncdefread_unicorn(name:str):ifname=="yolo":raiseUnicornException(name=name)return{"unicorn_name":name}

流程

  1. 业务代码raise UnicornException
  2. FastAPI 捕获后调用注册的unicorn_exception_handler
  3. 处理器返回自定义的JSONResponse

2. 处理器签名

asyncdefhandler(request:Request,exc:SomeException)->Response:...
参数类型说明
requestRequest当前请求对象
exc异常类实例被抛出的异常对象

三、覆盖默认异常处理器

FastAPI 内置两个默认处理器,可以被覆盖:

1. RequestValidationError 处理器

默认行为:返回 422 + 详细校验错误信息。

fromfastapi.exceptionsimportRequestValidationErrorfromfastapi.responsesimportPlainTextResponse@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request,exc):returnPlainTextResponse(str(exc),status_code=400)

2. HTTPException 处理器

fromstarlette.exceptionsimportHTTPExceptionasStarletteHTTPException@app.exception_handler(StarletteHTTPException)asyncdefhttp_exception_handler(request,exc):returnPlainTextResponse(f"Oops!{exc.detail}",status_code=exc.status_code)

注意:覆盖HTTPException处理器时,应导入starlette.exceptions.HTTPException,而非fastapi.HTTPException。FastAPI 的HTTPException继承自 Starlette 的版本,但增加了headers等额外功能。


四、异常处理优先级

请求进入 │ ├─ 业务代码 raise CustomException → 匹配 @app.exception_handler(CustomException) │ ├─ 业务代码 raise HTTPException → 匹配 @app.exception_handler(HTTPException) │ (未覆盖则走默认处理器) │ ├─ 请求校验失败 → RequestValidationError → 匹配对应处理器 │ └─ 未捕获异常 → 500 Internal Server Error(默认处理器)

匹配规则:按异常类的继承链,从具体到通用匹配。子类异常优先匹配子类处理器。


五、统一响应格式实践

实际项目中,通常需要统一的错误响应格式:

fromfastapiimportFastAPI,Request,HTTPExceptionfromfastapi.exceptionsimportRequestValidationErrorfromfastapi.responsesimportJSONResponsefrompydanticimportBaseModel app=FastAPI()# ---- 统一响应模型 ----classErrorResponse(BaseModel):code:intmessage:strdetail:object=None# ---- 统一错误返回函数 ----deferror_response(code:int,message:str,detail=None,status_code:int=None):returnJSONResponse(status_code=status_codeorcode,content=ErrorResponse(code=code,message=message,detail=detail).model_dump(),)# ---- HTTPException 处理器 ----@app.exception_handler(HTTPException)asyncdefhttp_exception_handler(request:Request,exc:HTTPException):returnerror_response(code=exc.status_code,message=exc.detailifisinstance(exc.detail,str)elsestr(exc.detail),status_code=exc.status_code,)# ---- 校验错误处理器 ----@app.exception_handler(RequestValidationError)asyncdefvalidation_exception_handler(request:Request,exc:RequestValidationError):returnerror_response(code=422,message="请求参数校验失败",detail=exc.errors(),status_code=422,)# ---- 兜底:未知异常 ----@app.exception_handler(Exception)asyncdefgeneric_exception_handler(request:Request,exc:Exception):returnerror_response(code=500,message="服务器内部错误",status_code=500,)

响应示例

{"code":422,"message":"请求参数校验失败","detail":[{"loc":["query","page"],"msg":"value is not a valid integer","type":"type_error.integer"}]}

六、HTTPException vs 自定义异常

对比项HTTPException自定义异常 +exception_handler
使用方式raise HTTPException(...)raise MyException(...)+ 注册处理器
适用场景简单的 HTTP 错误返回需要自定义逻辑/格式的错误处理
响应控制直接指定 status_code在处理器中灵活控制
可复用性通用可封装业务语义
是否中断代码是(raise)是(raise)

七、注意事项

  1. raise而非returnHTTPException是 Python 异常,必须raise,否则不会触发错误处理流程。
  2. 不要在处理器中再抛异常:异常处理器中如果再次raise,可能导致无限循环或 500 错误。
  3. 生产环境隐藏细节RequestValidationError默认返回详细的字段校验信息,生产环境建议精简,避免泄露接口结构。
  4. 日志记录:在异常处理器中添加日志,便于排查问题:
importlogging logger=logging.getLogger(__name__)@app.exception_handler(Exception)asyncdefgeneric_exception_handler(request:Request,exc:Exception):logger.exception(f"Unhandled exception:{exc}")returnerror_response(code=500,message="服务器内部错误",status_code=500)
  1. 异步/同步均可exception_handler支持同步和异步函数,但推荐使用async def
← 返回列表