如何强制所有异常都经过FastAPI中间件?

问题描述 投票:0回答:1

我正在使用 python

fastapi
库编写一个应用程序。我的部分代码引发了我需要处理的不同异常。我希望所有处理都在一个地方完成(根据引发的异常,使用不同的 except 块)。我尝试通过将以下(简化的)中间件添加到我的 FastAPI 应用程序中来做到这一点:

from fastapi import APIRouter, FastAPI, Request, HTTPException, Response, status
from starlette.middleware.base import BaseHTTPMiddleware
from fastapi.responses import JSONResponse

class ExceptionHandlerMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        try:
            return await call_next(request)
        except HTTPException as e:
            return JSONResponse(status_code=e.status_code, content={'message': e.detail})
        except Exception as e:
            return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={'message': str(e)})

# app creation and config go here....

app.add_middleware(ExceptionHandlerMiddleware)

问题是,这对于 fastapi 默认处理的某些特定异常不起作用(例如,如果引发

HTTPException
,它永远不会到达我的中间件中的 except 块,因为在到达中间件)

Fastapi 文档提供了一种方法来覆盖特定异常的默认行为,但这很乏味且不可扩展。有没有办法全局强制所有异常处理通过我的中间件? (如果有人知道一种不使用装饰器的方法来做到这一点,那就加分,因为我的一个要求就是不使用它们)

更新:我的问题最初被关闭为这个问题的重复,但它不是同一件事。这个问题涉及捕获未处理的异常,在我的问题中,我正在处理强制处理默认处理的异常(如

HTTPException
)在我控制的代码中的其他地方发生(如我的问题中所述,试图捕获中间件中的
HTTPException
不起作用!(这将是链接问题的要点))

python exception fastapi middleware starlette
1个回答
0
投票

Starlette 的

HTTPException
errors 不同,可以使用
try-except
块来处理引发的任何
Exception
(或从
Exception
派生的子类)。因此,您需要一个自定义异常处理程序来处理 FastAPI/Starlette 的
HTTPException
s。

请注意,以下示例使用了这个答案这个答案这个答案以及这个答案这个答案这个答案中解释的代码和详细信息。

此外,我强烈建议阅读 Starlette 有关异常的文档FastAPI 有关 Starlette 的

HTTPException
的文档。正如 FastAPI 文档中所述:

...

因此,您可以像平常一样继续提高 FastAPI 的

HTTPException
你的代码。

但是当你注册异常处理程序时,你应该注册 它 适合 Starlette 的

HTTPException

这样,如果 Starlette 内部代码的任何部分,或者 Starlette 扩展或插件,引发 Starlette

HTTPException
,您的处理程序 将能够抓住并处理它。

在此示例中,能够将两个

HTTPException
放在同一个 代码中,Starlette 的异常被重命名为
StarletteHTTPException
:

from starlette.exceptions import HTTPException as StarletteHTTPException 

示例

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


app = FastAPI() 


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    # Do some logging here
    print(exc.detail)
    return JSONResponse(content={"detail (specify as desired)": exc.detail}, status_code=exc.status_code)


@app.middleware("http")
async def exception_handling_middleware(request: Request, call_next):
    try:
        return await call_next(request)
    except Exception as e:
        # Do some logging here
        print(str(e))
        return JSONResponse(content="Something went wrong", status_code=500)
        
  
@app.get('/')
async def index():
    raise HTTPException(detail="Bad Request", status_code=400)
    

@app.get('/result')
async def get_result():
    return 1 + '0'  # this should raise an error
© www.soinside.com 2019 - 2024. All rights reserved.