starlette
starlette copied to clipboard
request body get empty when using middleware to save request to contextvar
I want to save request to ContextVar so I can use it anywhere. Here is code sample:
from contextvars import ContextVar
import uvicorn
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
ctx: ContextVar[Request] = ContextVar("request")
app = FastAPI()
class RequestContextMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
token = ctx.set(request)
try:
response = await call_next(request)
finally:
ctx.reset(token)
return response
app.add_middleware(RequestContextMiddleware)
async def root(request: Request, body: str):
print(1, request._stream_consumed)
print(2, request._body)
ctx_request = ctx.get()
print(3, ctx_request._body)
app.add_api_route("/", root, methods=["POST"])
if __name__ == '__main__':
uvicorn.run(app)
Output:
1 True
2 "the request data"
...
print(ctx_request._body)
^^^^^^^^^^^^^^^^^
AttributeError: '_CachedRequest' object has no attribute '_body'. Did you mean: 'body'?
so, my question is
- Why middleware will read body?
- Why the ctx_request._body get empty, but the request._body in param is worked
I'm not sure I understood your question / problem but _body is a private attribute that you should not be accessing or interacting with. Maybe try await request.body()?
I'm not sure I understood your question / problem but
_bodyis a private attribute that you should not be accessing or interacting with. Maybe tryawait request.body()?
@adriangb I used await request.body() before, but it raised an error:
raise RuntimeError("Stream consumed")
RuntimeError: Stream consumed
After investigation, I found out that _body was missing and _stream_consumed is True after middleware processed.
And I discovered similar topic in the discussion, which might be related. https://github.com/encode/starlette/discussions/2556
Let's continue the discussion there then.
This doesn't seem an issue, also the script on the description is using private attributes that shouldn't be used to demonstrate an issue.