在中间件上下文中获取starlette请求正文

问题描述

我有这样的中间件

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...