Python Web框架-全局异常处理 作者:马育民 • 2026-08-15 15:54 • 阅读:10001 # 提出问题 在 [Python Web框架-异常处理](https://www.malaoshi.top/show_1GW3ro5btgLh.html "Python Web框架-异常处理") 例子中,发现抛错时的返回格式,与成功运行时的返回格式不一致: 成功运行返回格式: ``` { "code": 200, "data": { "name": "李雷", "age": 21 } } ``` 报错返回格式: ``` { "detail": "没有此学号的学生" } ``` ### 分析 应该保持一致: ``` { "code": 200, // 都有状态码 "msg": "", // 报错时显示错误信息 "data": { // 查询数据时,返回数据。报错无此项 "name": "李雷", "age": 21 } } ``` ### 解决 使用全局异常处理 # 介绍 语法:`@app.exception_handler(捕获的异常类)`,函数参数接收 `request, exc`。 # 1. 捕获 HTTPException,统一返回格式 ### 例子 ```python from fastapi import FastAPI, HTTPException from starlette import status from starlette.requests import Request from starlette.responses import JSONResponse app = FastAPI() # 重写HTTPException返回格式 @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): return JSONResponse( status_code=exc.status_code, content={ "code": exc.status_code, "msg": exc.detail, # "data": None # 抛异常时,一般没有data } ) @app.get('/student/{id}') async def get_student(id: int): if id == 1: ret = { "code":200, "data":{ 'name': '李雷', 'age': 21, } } else: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail='没有此学号的学生' ) return ret ``` ### 测试报错 访问 http://127.0.0.1:8000/student/2 ,浏览器显示如下: ```json { "code": 404, "msg": "没有此学号的学生" } ``` 与返回成功数据的格式是一致的 # 2. 捕获 Python 原生异常 捕获程序所有未处理异常,例如 `ZeroDivisionError`、`KeyError`,**避免直接返回500原始堆栈给前端**,全局兜底 ```python from fastapi import FastAPI from starlette.requests import Request from starlette.responses import JSONResponse app = FastAPI() # 重写HTTPException返回格式 @app.exception_handler(Exception) async def http_exception_handler(request: Request, exc: Exception): return JSONResponse( status_code=500, content={ "code": 500, "msg": "".join(exc.args), # "data": None # 抛异常时,一般没有data } ) @app.get('/div/{a}/{b}') async def div(a: int, b: int): res = a/b return { "code":200, "msg":f"结果:{res}", } ``` ### 测试报错 浏览器发请求:http://127.0.0.1:8000/div/2/0 ,浏览器显示如下: ``` { "code": 500, "msg": "division by zero" } ``` 与返回成功数据的格式是一致的 ### 注意 `Exception` 处理器一定要放在最后,它会捕获所有未被前面处理器接住的异常。 # 3. 无法被 exception_handler 捕获的场景 ### 1 BackgroundTasks 后台任务抛出异常 后台任务不在请求路由生命周期,`exception_handler` **完全捕获不到**,会直接打印堆栈到控制台,接口已经返回给客户端。 > 解决:后台任务内部必须手动 try‑except。 ```python from fastapi import BackgroundTasks def task(): 1/0 # 这里报错,全局异常处理器捕获不到! @app.get("/bg") def bg(bt:BackgroundTasks): bt.add_task(task) return {"ok":True} ``` ### 2 普通asyncio.create_task() 创建任务 同理,脱离request上下文,异常处理器无效,必须任务内部捕获。 ### 3 中间件内部抛出异常 - 如果是 `@app.middleware("http")` 中间件中抛出异常:**可以被exception_handler捕获**。 - 注意:中间件中如果已经`await call_next(request)`拿到response之后,再抛异常,不会被处理。 原文出处:/show_1GW3ro61nCXj.html