我正在使用 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
不起作用!(这将是链接问题的要点))
Starlette 的
HTTPException
与 errors 不同,可以使用 try-except
块来处理引发的任何 Exception
(或从 Exception
派生的子类)。因此,您需要一个自定义异常处理程序来处理 FastAPI/Starlette 的 HTTPException
s。
请注意,以下示例使用了这个答案、这个答案、这个答案以及这个答案、这个答案和这个答案中解释的代码和详细信息。
此外,我强烈建议阅读 Starlette 有关异常的文档 和 FastAPI 有关 Starlette 的
HTTPException
的文档。正如 FastAPI 文档中所述:
...
因此,您可以像平常一样继续提高 FastAPI 的
你的代码。HTTPException
但是当你注册异常处理程序时,你应该注册 它 适合 Starlette 的
。HTTPException
这样,如果 Starlette 内部代码的任何部分,或者 Starlette 扩展或插件,引发 Starlette
,您的处理程序 将能够抓住并处理它。HTTPException
在此示例中,能够将两个
放在同一个 代码中,Starlette 的异常被重命名为HTTPException
: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