FastAPI middleware peeking into responses

时光怂恿深爱的人放手 提交于 2020-08-25 09:16:32

问题


I try to write a simple middleware for FastAPI peeking into response bodies.

In this example I just log the body content:

app = FastAPI()

@app.middleware("http")
async def log_request(request, call_next):
    logger.info(f'{request.method} {request.url}')
    response = await call_next(request)
    logger.info(f'Status code: {response.status_code}')
    async for line in response.body_iterator:
        logger.info(f'    {line}')
    return response

However it looks like I "consume" the body this way, resulting in this exception:

  ...
  File ".../python3.7/site-packages/starlette/middleware/base.py", line 26, in __call__
    await response(scope, receive, send)
  File ".../python3.7/site-packages/starlette/responses.py", line 201, in __call__
    await send({"type": "http.response.body", "body": b"", "more_body": False})
  File ".../python3.7/site-packages/starlette/middleware/errors.py", line 156, in _send
    await send(message)
  File ".../python3.7/site-packages/uvicorn/protocols/http/httptools_impl.py", line 515, in send
    raise RuntimeError("Response content shorter than Content-Length")
RuntimeError: Response content shorter than Content-Length

Trying to look into the response object I couldn't see any other way to read its content. What is the correct way to do it?


回答1:


I had a similar need in a FastAPI middleware and although not ideal here's what we ended up with:

app = FastAPI()

@app.middleware("http")
async def log_request(request, call_next):
    logger.info(f'{request.method} {request.url}')
    response = await call_next(request)
    logger.info(f'Status code: {response.status_code}')
    body = b""
    async for chunk in response.body_iterator:
        body += chunk
    # do something with body ...
    return Response(
        content=body,
        status_code=response.status_code,
        headers=dict(response.headers),
        media_type=response.media_type
    )

Be warned that such an implementation is problematic with responses streaming a body that would not fit in your server RAM (imagine a response of 100GB).

Depending on what your application does, you will rule if it is an issue or not.


In the case where some of your endpoints produce large responses, you might want to avoid using a middleware and instead implement a custom ApiRoute. This custom ApiRoute would have the same issue with consuming the body, but you can limit it's usage to a particular endpoints.

Learn more at https://fastapi.tiangolo.com/advanced/custom-request-and-route/



来源:https://stackoverflow.com/questions/60778279/fastapi-middleware-peeking-into-responses

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!