fastapi自定义中间处理过程

自定义中间件-Middleware

在FastAPI应用中使用中间件。中间件实际上是一个函数,在每个request处理之前被调用,同时又在每个response返回之前被调用。

  1. 首先接收访问过来的request。
  2. 然后针对request或其他功能执行自定义逻辑。
  3. 传递request给应用程序继续处理。
  4. 接收应用所产生的response。
  5. 然后针对response或其他功能执行自定义逻辑。
  6. 返回response。

详细说明可看官方文档:https://fastapi.tiangolo.com/tutorial/middleware/?h=middleware

下面是无敌哥pity平台代码,详细可看git仓库(https://github.com/wuranxu/pity)

asyncdef set_body(request: Request, body: bytes):
asyncdef receive() -> Message:
return {"type": "http.request", "body": body}

request._receive = receive


asyncdef get_body(request: Request) -> bytes:
body = await request.body()
await set_body(request, body)
return body


@pity.middleware("http")
asyncdef errors_handling(request: Request, call_next):
body = await request.body()
try:
await set_body(request, await request.body())
returnawait call_next(request)
except Exception as exc:
return JSONResponse(
status_code=status.HTTP_200_OK,
content=jsonable_encoder({
"code": 110,
"msg": str(exc),
"request_data": body,
})
)

参考issues:https://github.com/tiangolo/fastapi/issues/394 https://stackoverflow.com/questions/61358669/raise-exception-in-python-fastapi-middleware

自定义路由类-APIRoute

在某些情况下,您可能希望覆盖Request和APIRoute类使用的逻辑。特别是,这可能是中间件中逻辑的一个很好的替代方案。例如,如果您想在应用程序处理请求正文之前读取或操作请求正文。详细说明可看官方文档:https://fastapi.tiangolo.com/advanced/custom-request-and-route

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

asyncdef custom_route_handler(request: Request) -> Union[Response]:
try:
returnawait original_route_handler(request)
except Exception as exc:
log_msg = f"造数平台捕获到系统错误:请求路径:{request.url.path}\n"
params = request.query_params
if params:
log_msg += f"路径参数:{params}\n"
boby = await request.body()
if boby:
body = json.dumps(json.loads(boby),ensure_ascii=False)
log_msg +=f"请求参数:{body}\n"
if isinstance(exc, NormalException):
return JSONResponse(
status_code=status.HTTP_200_OK,
content={
"responseCode": Status.SYSTEM_EXCEPTION.get_code(),
"responseMsg": exc.errorMsg
},
)
elif isinstance(exc, RequestValidationError):
message = ""
for error in exc.errors():
message += str(error.get('loc')[-1]) + ":" + str(error.get("msg")) + ","
return JSONResponse(
status_code=status.HTTP_200_OK,
content=jsonable_encoder({
"responseCode": Status.PARAM_ILLEGAL.get_code(),
"responseMsg": Status.PARAM_ILLEGAL.get_msg() + message[:-1]
})
)
log_msg +=f"错误信息:{str(exc.args[0])}"
mylog.error(log_msg)
if PlatConfig.SWITCH == 1:
WeGroupChatBot.send_text(log_msg)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=jsonable_encoder({
"responseCode": Status.FAIL.get_code(),
"responseMsg": Status.FAIL.get_msg(),
"errorMsg":str(exc.args[0])
},
))
return custom_route_handler

def APIRouter():
router = AppRouter()
router.route_class = ErrorRouter
return router

统一处理之后,再通过类型判断Exception,返回不同的Response~ 

注意:用了自定义错误路由,就不能再用 「@app.exception_handler」否则会重复捕获!!!

参考issues:https://github.com/tiangolo/fastapi/issues/1216 https://github.com/tiangolo/fastapi/issues/2750

posted on 2022-07-28 18:55  帅胡  阅读(622)  评论(0编辑  收藏  举报

导航