FastAPI中间件窥探响应 [英] FastAPI middleware peeking into responses

查看:181
本文介绍了FastAPI中间件窥探响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写一个简单的中间件,用于FastAPI窥探响应主体.

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?

推荐答案

我在FastAPI中间件中也有类似的需求,尽管不理想,但这是我们最终得到的东西:

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
    )

请注意,这样的实现会在响应流式传输的内容不适合您服务器RAM的情况下出现问题(想象响应为100GB).

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.

在某些端点产生较大响应的情况下,您可能希望避免使用中间件,而是实现自定义ApiRoute.这种自定义的ApiRoute在消耗主体方面会遇到相同的问题,但是您可以将其用法限制为特定的端点.

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.

请访问> https://fastapi.tiangolo.com/advanced/custom-request-and-route/

这篇关于FastAPI中间件窥探响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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