12

在 FastAPI 框架内:

虽然请求数据当然可以作为参数传递,但我想知道函数是否可以在不传递参数的情况下访问有关当前请求的信息。

免责声明:我不认为全局访问请求数据是一个好的做法,但我有一个用例,如果能够做到这一点会非常好。

4

4 回答 4

16

此处提供的解决方案定义了一个上下文管理器,您可以全局访问它。对于每个请求,您都在提取相关信息(如标头)并将其传递给上下文管理器。

由于 fastapi 是使用Starlette构建的,因此您可以使用 library starlette-context。它正在创建一个context您可以在不将其作为参数传递的情况下使用的对象。主要的警告是您仍然需要将请求对象传递给您的所有路由。

编辑:在starlette-context==0.3.0新的中间件中添加了。Starlette团队开始不鼓励(在这里)使用他们的BaseHTTPMiddleware,特别是对于 StreamingResponse/FileResponse 端点。您可能想要使用RawContextMiddleware它也不需要请求对象,但它是实验性的,因为没有Starlette用于编写没有接口的自定义中间件的文档。但它似乎正在工作。

此库中的示例代码用于说明:

import uvicorn
from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.middleware import Middleware

from starlette_context import context, plugins
from starlette_context.middleware import ContextMiddleware

middleware = [
    Middleware(
        ContextMiddleware,
        plugins=(
            plugins.RequestIdPlugin(),
            plugins.CorrelationIdPlugin()
        )
    )
]

app = FastAPI(debug=True, middleware=middleware)


@app.route('/')
async def index(request: Request):  # This argument is still needed here
    return JSONResponse(context.data)  # Your context data


uvicorn.run(app, host="0.0.0.0")
于 2020-04-17T12:43:04.240 回答
2

request.state您可以从 Starlette获取/设置任意属性。

https://www.starlette.io/requests/#other-state

详细解释和实现请参考以下问题:

https://github.com/tiangolo/fastapi/issues/633

于 2019-12-06T06:23:36.750 回答
0

我通常会使用生产者-消费者风格的消息队列来做到这一点。我有一个示例 repo,展示了如何使用全局队列将数据从发布请求推送到将其广播给客户端的 WebSocket。

虽然这可能不是您的确切用例,但您应该能够对其进行调整以适应。

它的核心是一个将数据推送到队列的 Notifier 类:

async def push(self, msg: str):
    await self.channel.default_exchange.publish(
        Message(msg.encode("ascii")),
        routing_key=self.queue_name,
    )

在消费者方面,我有一个_notify从队列接收消息并通过 WebSocket 发送的函数:

async def _notify(self, message: IncomingMessage):
    living_connections = []
    while len(self.connections) > 0:
        websocket = self.connections.pop()
        await websocket.send_text(f"{message.body}")
        living_connections.append(websocket)
    self.connections = living_connections
于 2019-10-19T15:35:08.440 回答
-1

你可以使用 starlette请求

例如:

from starlette.requests import Request
from fastapi import FastApi

app = FastApi()
@app.get('/')
def get(request:Request):
    requests_header = request.headers
    return "Hi"
于 2020-03-07T17:23:23.363 回答