Python Web框架-FastAPI教程-全局异常处理

介绍

在国内后端开发中,几乎所有公司都遵循一套固定响应规范:

无论成功还是失败,HTTP 状态码永远返回 200;通过自定义业务码 code 判断请求状态。

而 FastAPI 默认返回格式杂乱、报错会直接抛出堆栈信息、不方便前端统一处理。

本文记录一套最简单、最标准、企业通用的写法:

  • ✅ 成功统一返回格式

  • ✅ 业务错误直接 raise 抛出,不用手写 JSON

  • ✅ 全局异常捕获,屏蔽后端报错堆栈

  • ✅ 完全符合国内前后端交互规范

设计思想

1、错误逻辑:抛出异常,统一处理

只要接口不符合业务条件,不要 return 错误 json。

直接:raise HTTPException\(业务码, 错误信息\)

由全局异常处理器统一封装返回结构。

2、正常逻辑:直接返回数据

业务正常时,调用封装好的成功函数,直接返回标准化数据。

3、国内规范铁律

HTTP 状态码一律 200,code 控制业务状态。

案例

全局HTTPException异常捕获

处理 HTTPException 异常

# ------------------------------
# 全局异常处理器:捕获主动抛出的业务异常(HTTPException异常)
# ------------------------------
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc: HTTPException):
    """
    统一处理手动抛出的业务异常
    国内规范:HTTP状态码永远200,code为自定义业务码
    """
    return JSONResponse(
        status_code=200,
        content={
            "code": exc.status_code,
            "message": exc.detail,
            "data": None
        }
    )

全局未知异常处理器

处理 非 HTTPException 异常

# ------------------------------
# 全局未知异常(非HTTPException异常)处理器:捕获代码bug、崩溃、报错
# ------------------------------
@app.exception_handler(Exception)
async def general_exception_handler(request, exc):
    """服务器未知错误,屏蔽堆栈信息"""
    return JSONResponse(
        status_code=200,
        content={
            "code": 500,
            "message": "服务器内部错误",
            "data": None
        }
    )

完整代码

from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse

app = FastAPI()

# ------------------------------
# 全局异常处理器:捕获主动抛出的业务异常(HTTPException异常)
# ------------------------------
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc: HTTPException):
    """
    统一处理手动抛出的业务异常
    国内规范:HTTP状态码永远200,code为自定义业务码
    """
    return JSONResponse(
        status_code=200,
        content={
            "code": exc.status_code,
            "message": exc.detail,
            "data": None
        }
    )

# ------------------------------
# 全局未知异常(非HTTPException异常)处理器:捕获代码bug、崩溃、报错
# ------------------------------
@app.exception_handler(Exception)
async def general_exception_handler(request, exc):
    """服务器未知错误,屏蔽堆栈信息"""
    return JSONResponse(
        status_code=200,
        content={
            "code": 500,
            "message": "服务器内部错误",
            "data": None
        }
    )

# ------------------------------
# 统一成功返回工具函数
# ------------------------------
def success_response(data=None, message: str = "请求成功"):
    """成功统一返回格式"""
    return {
        "code": 200,
        "message": message,
        "data": data
    }

业务接口写法

业务错误:直接抛异常

@app.get("/user/{user_id}")
async def get_user(user_id: int):
    # 不满足条件:直接抛异常,不用写return
    if user_id <= 0:
        raise HTTPException(status_code=400, detail="用户ID不合法")

    # 模拟查询用户
    user_info = {
        "id": user_id,
        "username": "测试用户",
        "age": 22
    }
    # 正常返回:调用成功封装函数
    return success_response(user_info)

最终返回格式

1、成功响应示例

{
    "code": 200,
    "message": "请求成功",
    "data": {
        "id": 10,
        "username": "测试用户",
        "age": 22
    }
}

2、业务错误响应示例

{
    "code": 400,
    "message": "用户ID不合法",
    "data": null
}

3、服务器未知错误示例

{
    "code": 500,
    "message": "服务器内部错误",
    "data": null
}

为什么要这样写?

1、业务代码极度干净

不需要在每个 if 判断里重复写错误 JSON。

不符合条件 → raise;正常逻辑 → return。

2、全站返回格式强制统一

无论谁写接口,格式永远一致,前端无需适配多种结构。

3、后期维护极其方便

如果后期要改返回字段(比如 message 改成 msg),只改一处,不用改全部接口。

4、隐藏服务器报错,安全性高

代码崩溃、数据库报错不会暴露堆栈信息,生产环境必备。

5、完全贴合国内开发规范

HTTP 状态码永远为 200,前端不用处理 http 异常拦截,只判断 code。

总结

  • 不符合业务条件:raise HTTPException(交给全局处理器)

  • 正常业务逻辑:return success_response()(统一成功格式)

  • 代码意外崩溃:自动走500异常(隐藏错误)

  • HTTP状态码永远200,code区分业务状态(国内规范)

拓展

后续可以在此基础上升级:

  1. 自定义业务异常枚举(1001未登录、1002密码错误)

  2. 异常自动日志记录

  3. 全局请求拦截、token校验

  4. 统一分页返回模板


原文出处:/show_1GW3HquMfBPO.html