Skip to content

47|全局异常处理与错误响应

接口运行过程中不可避免地会出错:数据库连接断开、参数校验失败、业务规则冲突。没有统一处理的异常会直接把 Python 堆栈返回给客户端,既暴露内部实现,又让用户看不懂。FastAPI 提供异常处理器(exception handler),把不同类型的异常转换为统一的错误响应格式。

一、HTTPException

FastAPI 内置的异常,用于主动返回 HTTP 错误:

python
from fastapi import HTTPException, status

@app.get("/servers/{id}")
async def get_server(id: int):
    server = find_server(id)
    if not server:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="服务器不存在",
        )
    return server
参数作用
status_codeHTTP 状态码
detail错误描述,返回给客户端
headers额外的响应头(如 401 时的 WWW-Authenticate

HTTPException 会被 FastAPI 自动捕获并转成 JSON 响应:

json
{"detail": "服务器不存在"}

二、自定义异常

业务逻辑复杂时,用自定义异常更清晰:

python
class BusinessError(Exception):
    def __init__(self, code: int, message: str):
        self.code = code
        self.message = message

class ResourceNotFound(BusinessError):
    def __init__(self, resource: str):
        super().__init__(code=1001, message=f"{resource} 不存在")

class PermissionDenied(BusinessError):
    def __init__(self):
        super().__init__(code=1002, message="权限不足")

服务层抛出业务异常:

python
def get_server(server_id: int) -> Server:
    server = db.get(Server, server_id)
    if not server:
        raise ResourceNotFound("服务器")
    return server

三、全局异常处理器

python
from fastapi import Request
from fastapi.responses import JSONResponse

@app.exception_handler(BusinessError)
async def business_error_handler(request: Request, exc: BusinessError):
    return JSONResponse(
        status_code=400,
        content={"code": exc.code, "message": exc.message, "data": None},
    )

@app.exception_handler(HTTPException)
async def http_error_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={"code": exc.status_code, "message": exc.detail, "data": None},
        headers=exc.headers,
    )

@app.exception_handler(Exception)
async def generic_error_handler(request: Request, exc: Exception):
    logger.exception("未处理的异常")
    return JSONResponse(
        status_code=500,
        content={"code": 500, "message": "服务器内部错误", "data": None},
    )
处理器捕获范围
BusinessError自定义业务异常
HTTPExceptionFastAPI 内置 HTTP 异常
Exception所有其他未捕获的异常(最后一道防线)

四、统一错误响应格式

python
class ErrorResponse(BaseModel):
    code: int
    message: str
    data: None = None

所有错误都按这个格式返回,前端只需要一套错误处理逻辑:

js
async function request(url, options) {
  const response = await fetch(url, options);
  const data = await response.json();

  if (data.code !== 0) {
    throw new Error(data.message);
  }
  return data.data;
}

五、Pydantic 校验错误定制

Pydantic 校验失败默认返回 422,格式是 FastAPI 固定的。可以定制为统一格式:

python
from fastapi.exceptions import RequestValidationError

@app.exception_handler(RequestValidationError)
async def validation_error_handler(request: Request, exc: RequestValidationError):
    errors = exc.errors()
    message = "; ".join([f"{'.'.join(map(str, e['loc']))}: {e['msg']}" for e in errors])

    return JSONResponse(
        status_code=422,
        content={"code": 422, "message": message, "data": None},
    )

六、隐藏生产环境堆栈

python
import os

ENV = os.getenv("ENV", "development")

@app.exception_handler(Exception)
async def generic_error_handler(request: Request, exc: Exception):
    logger.exception("未处理的异常")

    content = {"code": 500, "message": "服务器内部错误", "data": None}
    if ENV == "development":
        content["detail"] = str(exc)   # 开发环境返回详细错误

    return JSONResponse(status_code=500, content=content)

生产环境只返回"服务器内部错误",不暴露堆栈;开发环境可以返回详细错误方便调试。

七、常见错误

异常处理器中再次抛异常

python
@app.exception_handler(Exception)
async def bad_handler(request, exc):
    raise AnotherException()   # 错误:处理器抛异常会导致服务崩溃

404 路由用 400 返回

python
# 错误:资源不存在用 400(Bad Request 是请求语法错误)
raise HTTPException(status_code=400, detail="服务器不存在")

# 正确
raise HTTPException(status_code=404, detail="服务器不存在")

忘记处理 Pydantic 校验错误

Pydantic 校验失败默认返回的格式和自定义的统一格式不一致,需要专门注册 RequestValidationError 处理器。