全局捕获快速 api 中的“异常”

Aje*_*ngh 13 exception python-3.x fastapi

我是非常新的 python 和 fastapi。我正在尝试在全局级别捕获未处理的异常。所以在main.py文件中的某个地方我写在下面:

@app.exception_handler(Exception)
async def exception_callback(request: Request, exc: Exception):
  logger.error(exc.detail)
Run Code Online (Sandbox Code Playgroud)

但上述方法从未执行过。但是如果我编写一个自定义异常并尝试捕获它(如下所示),它运行良好。

class MyException(Exception):
  #some code

@app.exception_handler(MyException)
async def exception_callback(request: Request, exc: MyException):
  logger.error(exc.detail)
Run Code Online (Sandbox Code Playgroud)

我已经完成了Catch 异常类型的 Exception 和 process body request #575。但是这个错误谈论访问请求正文。看到这个bug,感觉应该可以抓到Exception。FastApi 版本fastapi>=0.52.0

提前致谢 :)

小智 14

你可以做这样的事情。它应该返回一个 json 对象,其中包含您的自定义错误消息,该对象也可以在调试器模式下工作。

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

app = FastAPI()

@app.exception_handler(Exception)
async def validation_exception_handler(request: Request, exc: Exception):
    # Change here to Logger
    return JSONResponse(
        status_code=500,
        content={
            "message": (
                f"Failed method {request.method} at URL {request.url}."
                f" Exception message is {exc!r}."
            )
        },
    )
Run Code Online (Sandbox Code Playgroud)

  • 如上所述,这仍然会产生“ASGI application_ 中的异常” (2认同)

And*_*ijo 11

如果您想捕获所有未处理的异常(内部服务器错误),有一种非常简单的方法。文档

from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import Response

app = FastAPI()

async def catch_exceptions_middleware(request: Request, call_next):
    try:
        return await call_next(request)
    except Exception:
        # you probably want some kind of logging here
        return Response("Internal server error", status_code=500)

app.middleware('http')(catch_exceptions_middleware)
Run Code Online (Sandbox Code Playgroud)

确保将此中间件放在其他所有东西之前。

  • 这等待所有任务完成。因此,它可以防止安排任务在后台运行。 (6认同)
  • “中间件”示例对我不起作用,但官方文档中“路由”的使用就像一个魅力https://fastapi.tiangolo.com/advanced/custom-request-and-route/#accessing-the -异常处理程序中的请求主体 (2认同)

mad*_*ox2 9

添加自定义APIRoute也可用于处理全局异常。这种方法的优点是,如果自定义路由引发 http 异常,Starlette 的默认错误处理程序将处理该异常:

from typing import Callable

from fastapi import Request, Response, HTTPException, APIRouter, FastAPI
from fastapi.routing import APIRoute
from .logging import logger


class RouteErrorHandler(APIRoute):
    """Custom APIRoute that handles application errors and exceptions"""

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            try:
                return await original_route_handler(request)
            except Exception as ex:
                if isinstance(ex, HTTPException):
                    raise ex
                logger.exception("uncaught error")
                # wrap error into pretty 500 exception
                raise HTTPException(status_code=500, detail=str(ex))

        return custom_route_handler


router = APIRouter(route_class=RouteErrorHandler)

app = FastAPI()
app.include_router(router)
Run Code Online (Sandbox Code Playgroud)

使用 fastapi==0.68.1 为我工作。

有关自定义路由的更多信息:https ://fastapi.tiangolo.com/advanced/custom-request-and-route/


zhf*_*fkt 6

这是 Fastapi 和 Starlette 上的一个已知问题。

我试图通过以下简单示例全局捕获 StarletteHTTPException。

import uvicorn

from fastapi import FastAPI
from starlette.requests import Request
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.responses import JSONResponse

app = FastAPI()


@app.exception_handler(StarletteHTTPException)
async def exception_callback(request: Request, exc: Exception):
    print("test")
    return JSONResponse({"detail": "test_error"}, status_code=500)


if __name__ == "__main__":
    uvicorn.run("test:app", host="0.0.0.0", port=1111, reload=True)


Run Code Online (Sandbox Code Playgroud)

有用。我打开浏览器并调用端点 / 并尝试访问http://127.0.0.1:1111/,它将返回 json {"detail":"test_error"} ,HTTP 代码为 "500 Internal Server Error" 。

浏览器上 500 IDE 中为 500

但是,当我只将 @app.exception_handler 中的 StarletteHTTPException 更改为 Exception 时,

import uvicorn

from fastapi import FastAPI
from starlette.requests import Request
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.responses import JSONResponse

app = FastAPI()


@app.exception_handler(Exception)
async def exception_callback(request: Request, exc: Exception):
    print("test")
    return JSONResponse({"detail": "test_error"}, status_code=500)


if __name__ == "__main__":
    uvicorn.run("test:app", host="0.0.0.0", port=1111, reload=True)

Run Code Online (Sandbox Code Playgroud)

当我访问http://127.0.0.1:1111/时,异常回调方法无法捕获 StarletteHTTPException 。报404错误。

浏览器404 IDE 中的 404

异常行为应该是: StarletteHTTPException 错误可以通过 Exception 修饰的方法 exception_handler 捕获,因为 StarletteHTTPException 是 Exception 的子类。

然而,这是 Fastapi 和 Starlette 中报告的一个已知问题

所以我们目前还无法实现这个目标。