You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI使用starlette-context插件如何获取request.body内容?

问题根因
  • 第一个报错的核心原因是你中间件配置中的plugins参数没有正确声明为元组:Python语法中单个元素的括号包裹内容默认识别为单个对象,只有加后缀逗号才会被判定为元组,starlette-context在遍历插件列表时没有正确执行该异步插件方法,导致request.body()协程未被调用,抛出警告。
  • 第二个路由无法接收请求的问题,是因为Starlette的请求体是流式结构,只能消费一次,你在插件中调用await request.body()之后,流已经读取到末尾,后续FastAPI路由层再读取请求体时会拿到空值。
修正方案

1. 自定义插件改造

读完请求体后将内容重新写入请求的流对象,保证后续链路可以正常读取:

from typing import Any, Optional, Union
import io
from starlette.requests import HTTPConnection, Request
from starlette_context.plugins import Plugin

class BodyPlugin(Plugin):
    key = "body"

    async def process_request(
        self, request: Union[Request, HTTPConnection]
    ) -> Optional[Any]:
        # 仅处理普通HTTP请求,跳过WebSocket等其他连接类型
        if not isinstance(request, Request):
            return None
        body = await request.body()
        # 重置请求流,让后续链路可以再次读取请求体
        request._stream = io.BytesIO(body)
        return body

2. 中间件配置修正

给plugins元组加后缀逗号,保证类型正确:

middleware = [
    Middleware(
        ContextMiddleware,
        plugins=(
            BodyPlugin(),
            # 单个元素必须加逗号,才会被识别为元组
        )
    )
]
注意事项
  • 大文件上传、流式请求的场景不建议全局采集请求体,会占用大量内存,可通过request.headers.get("content-type")判断请求类型后跳过采集。
  • 如果请求体是压缩格式(gzip/deflate),需要先解压再存储,否则采集到的是二进制压缩内容。

内容的提问来源于stack exchange,提问作者Xing Liu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 08:30:01