FASTAPI定制中间件内部获取请求体 [英] FASTAPI custom middleware getting body of request inside

查看:24
本文介绍了FASTAPI定制中间件内部获取请求体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图使用FASTAPI中间件获取请求的正文,但似乎只能获取quest.Header,而不能获取正文。我需要身体,以便获得一个密钥,我将使用它来检查数据库中的某些东西。考虑中间件的日志记录或身份验证使用。

@app.middleware("http")
    async def TestCustomMiddleware(request: Request, call_next):
    print("Middleware works!", request.headers)

    response = await call_next(request)
    resp_body = [section async for section in response.__dict__['body_iterator']]
    print("BODY:", resp_body)
    return response

我可以获取此信息,但出现错误将中断POST请求:

INFO:     Started server process [37160]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
Middleware works! Headers({'content-type': 'application/json', 'user-agent': 'PostmanRuntime/7.26.8', 'accept': '*/*', 'cache-control': 'no-cache', 'postman-token': 'ca6839ec-833d-45c0-9b52-8f904db13966', 'host': 'localhost:8000', 'accept-encoding': 'gzip, deflate, br', 'connection': 'keep-alive', 'content-length': '12'})
BODY: [b'{"test":"1"}']
INFO:     127.0.0.1:60761 - "POST /jctest HTTP/1.1" 200 OK
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "C:PythonPython38libsite-packagesuvicornprotocolshttphttptools_impl.py", line 386, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "C:PythonPython38libsite-packagesuvicornmiddlewareproxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "C:PythonPython38libsite-packagesfastapiapplications.py", line 181, in __call__
    await super().__call__(scope, receive, send)
  File "C:PythonPython38libsite-packagesstarletteapplications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "C:PythonPython38libsite-packagesstarlettemiddlewareerrors.py", line 181, in __call__
    raise exc from None
  File "C:PythonPython38libsite-packagesstarlettemiddlewareerrors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "C:PythonPython38libsite-packagesstarlettemiddlewarease.py", line 26, in __call__
    await response(scope, receive, send)
  File "C:PythonPython38libsite-packagesstarlette
esponses.py", line 228, in __call__
    await run_until_first_complete(
  File "C:PythonPython38libsite-packagesstarletteconcurrency.py", line 18, in run_until_first_complete
    [task.result() for task in done]
  File "C:PythonPython38libsite-packagesstarletteconcurrency.py", line 18, in <listcomp>
    [task.result() for task in done]
  File "C:PythonPython38libsite-packagesstarlette
esponses.py", line 225, in stream_response
    await send({"type": "http.response.body", "body": b"", "more_body": False})
  File "C:PythonPython38libsite-packagesstarlettemiddlewareerrors.py", line 156, in _send
    await send(message)
  File "C:PythonPython38libsite-packagesuvicornprotocolshttphttptools_impl.py", line 516, in send
    raise RuntimeError("Response content shorter than Content-Length")
RuntimeError: Response content shorter than Content-Length

如何修复此问题才能获取{"test":"1"}的请求正文?

正在尝试获取正文以查找将用于检查数据库的密钥,并根据凭据授予对API的访问权限或拒绝访问。

推荐答案

您需要await请求,这样请求对象实际上就可以读取了。我就是这样做到的。

class RequestContextLogMiddleware(BaseHTTPMiddleware):

    async def set_body(self, request: Request):
        receive_ = await request._receive()

        async def receive() -> Message:
            return receive_

        request._receive = receive

    async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
        await self.set_body(request)
        body = await request.body()
        jsonbody = await request.json()
        id_ = jsonbody['external_id']
        response = await call_next(request)    
        return response

这篇关于FASTAPI定制中间件内部获取请求体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆