如何正确组合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)
不会抛出任何异常
这个问题如何解决?
一方面我们需要不同功能的中间件代码,另一方面一些异常(不正确的参数等)应该在中间代码之前或内部进行跟踪,但不能更深入。
您应该在中间件中重新引发
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)
一种方法是
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