fastapi:中间件中的异常(RequestValidationError)跟踪

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

如何正确组合RequestValidationError异常处理函数

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    response = prepare_response({}, g_ERROR__INCORRECT_PARAMS)

    return JSONResponse(content=response)

和中间件代码函数

@app.middleware("http")
async def response_middleware(request: Request, call_next):
    try:
        result = await call_next(request)

        res_body = b''
        async for chunk in result.body_iterator:
            res_body += chunk

        response = prepare_response(res_body.decode(), g_ERROR__ALL_OK)
    except Exception as e:
        response = prepare_response({}, g_ERROR__UNKNOWN_ERROR)

    return JSONResponse(content=response)

只有 RequestValidationError 异常才会触发该函数

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):

以及所有其他情况下的功能

@app.middleware("http")
async def response_middleware(request: Request, call_next):

现在

response_middleware
函数一直触发并处理
validation_exception_handler
的结果,这违反了函数的基本意图

使用

@app.middleware("http")
时,任何异常都会消失,即使没有
@app.exception_handler(RequestValidationError)
,代码也会始终生成
200 OK

    try:
        result = await call_next(request)

        res_body = b''
        async for chunk in result.body_iterator:
            res_body += chunk

        response = prepare_response(res_body.decode(), g_ERROR__ALL_OK)
    except RequestValidationError as e:
        response = prepare_response({}, g_ERROR__INCORRECT_PARAMS)
    except Exception as e:
        response = prepare_response({}, g_ERROR__UNKNOWN_ERROR)

也不起作用 - 之后根本不起作用

result = await call_next(request)

不会抛出任何异常

这个问题如何解决?

一方面我们需要不同功能的中间件代码,另一方面一些异常(不正确的参数等)应该在中间代码之前或内部进行跟踪,但不能更深入。

python exception fastapi middleware fastapi-middleware
2个回答
0
投票

您应该在中间件中重新引发

RequestValidationError
异常。

尝试更改您的中间件代码,如下所示:

@app.middleware("http")
async def response_middleware(request: Request, call_next):
    try:
        result = await call_next(request)

        res_body = b''
        async for chunk in result.body_iterator:
            res_body += chunk

        response = prepare_response(res_body.decode(), g_ERROR__ALL_OK)
    except RequestValidationError as e:
        raise # Re-raise exception!
    except Exception as e:
        response = prepare_response({}, g_ERROR__UNKNOWN_ERROR)

    return JSONResponse(content=response)

0
投票

一种方法是

raise
自定义 
RequestValidationError
 中的任何 
validation_exception_handler
异常,然后在中间件中的
try-except
周围使用
await call_next(request)
捕获它们 — 请看一下 这个答案(选项 1 和 2)、此答案(选项 4)和 此答案(选项 1)了解完整的工作示例。

但是,最直接的方法可能只是检查

status_code
response
,以及它是否在指定的范围内(例如,在
400
599
之间 HTTP 响应状态代码,表示客户端或服务器错误),或者如果只是
422
(正如您提到的,只有
RequestValidationError
异常需要与其他响应/异常进行不同的处理),然后相应地处理响应。在处理 FastAPI 中的 middleware 时,您也可能会受益于查看
这个答案

工作示例

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

app = FastAPI()


@app.middleware("http")
async def custom_middleware(request: Request, call_next):
    response = await call_next(request)
    
    #if 399 < response.status_code < 600:
    if response.status_code == 422:
        # return Exception response as is
        return response
        
        # or return some custom response
        #return JSONResponse(status_code=422, content={"msg": "custom"})
        
    else: # do whatever
        return response
    

class Demo(BaseModel):
    content: str


@app.post('/')
async def main(demo: Demo):
    return demo
© www.soinside.com 2019 - 2024. All rights reserved.