问题描述
我有这样的中间件
val testDependencies = Seq(
"org.scalatest" %% "scalatest" % "3.2.0" % "test"
)
val miscDependencies = Seq(
"com.github.tototoshi" %% "scala-csv" % "1.3.6","org.lz4" % "lz4-java" % "1.5.1","org.json4s" %% "json4s-jackson" % "3.6.1","org.apache.hadoop" % "hadoop-common" % "3.2.1","redis.clients" % "jedis" % "2.9.0","com.googlecode.plist" % "dd-plist" % "1.21","com.couchbase.client" % "java-client" % "2.7.14","org.apache.parquet" % "parquet-avro" % "1.11.1",)
val flinkDependencies = Seq(
"org.apache.flink" %% "flink-scala" % flinkVersion % "provided","org.apache.flink" %% "flink-streaming-scala" % flinkVersion % "provided","org.apache.flink" % "flink-s3-fs-hadoop" % flinkVersion % "provided","org.apache.flink" % "flink-metrics-dropwizard" % flinkVersion,"org.apache.flink" % "flink-formats" % flinkVersion pomOnly(),"org.apache.flink" % "flink-compress" % flinkVersion,"org.apache.flink" %% "flink-statebackend-rocksdb" % flinkVersion,"org.apache.flink" %% "flink-clients" % flinkVersion,"org.apache.flink" %% "flink-parquet" % flinkVersion
)
因此,行class RequestContext(BaseHTTPMiddleware):
async def dispatch(self,request: Request,call_next: RequestResponseEndpoint):
request_id = request_ctx.set(str(uuid4())) # generate uuid to request
body = await request.body()
if body:
logger.info(...) # log request with body
else:
logger.info(...) # log request without body
response = await call_next(request)
response.headers['X-Request-ID'] = request_ctx.get()
logger.info("%s" % (response.status_code))
request_ctx.reset(request_id)
return response
冻结了所有具有body的请求,而我的请求中有504个。在这种情况下,我如何安全地阅读请求正文?我只想记录请求参数。
解决方法
如果您仍然想使用BaseHTTP,我最近遇到了这个问题并提出了解决方案:
中间件代码
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
import json
from .async_iterator_wrapper import async_iterator_wrapper as aiwrap
class some_middleware(BaseHTTPMiddleware):
async def dispatch(self,request:Request,call_next:RequestResponseEndpoint):
# --------------------------
# DO WHATEVER YOU TO DO HERE
#---------------------------
response = await call_next(request)
# Consuming FastAPI response and grabbing body here
resp_body = [section async for section in response.__dict__['body_iterator']]
# Repairing FastAPI response
response.__setattr__('body_iterator',aiwrap(resp_body)
# Formatting response body for logging
try:
resp_body = json.loads(resp_body[0].decode())
except:
resp_body = str(resp_body)
async_iterator_wrapper代码 来自 TypeError from Python 3 async for loop
class async_iterator_wrapper:
def __init__(self,obj):
self._it = iter(obj)
def __aiter__(self):
return self
async def __anext__(self):
try:
value = next(self._it)
except StopIteration:
raise StopAsyncIteration
return value
我真的希望这可以对某人有所帮助!我发现这对日志记录很有帮助。
非常感谢@Eddified提供的aiwrap类
,我不会创建从BaseHTTPMiddleware继承的中间件,因为它具有一些issues,FastAPI给您提供了创建自己的路由器的机会,以我的经验,这种方法更好。
from fastapi import APIRouter,FastAPI,Request,Response,Body
from fastapi.routing import APIRoute
from typing import Callable,List
from uuid import uuid4
class ContextIncludedRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
request_id = str(uuid4())
response: Response = await original_route_handler(request)
if await request.body():
print(await request.body())
response.headers["Request-ID"] = request_id
return response
return custom_route_handler
app = FastAPI()
router = APIRouter(route_class=ContextIncludedRoute)
@router.post("/context")
async def non_default_router(bod: List[str] = Body(...)):
return bod
app.include_router(router)
按预期工作。
b'["string"]'
INFO: 127.0.0.1:49784 - "POST /context HTTP/1.1" 200 OK