定制请求#

定制上下文#

默认情况下,应用程序上下文是 SimpleNamespace,允许你在其上设置任何你想要的属性。但是,你也可以选择传递任何其他对象。

app = Sanic(..., ctx=1)
app = Sanic(..., ctx={})
class MyContext:
    ...

app = Sanic(..., ctx=MyContext())

在大型代码库中拥有类型化的请求上下文对象非常便利。当然这不是必需的,但可能非常有用。

from sanic import Sanic, Request
from types import SimpleNamespace

class CustomRequest(Request):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.ctx.user_id = self.headers.get("X-User-ID")

    @staticmethod
    def make_context() -> CustomContext:
        return CustomContext()

@dataclass
class CustomContext:
    user_id: str = None

定制请求上下文#

有时候,拥有你自己的 Request 类并告诉 Sanic 使用它而不是默认的类是有帮助的。

一个例子是如果你想修改默认的 request.id 生成器。

import time

from sanic import Request, Sanic, text

class NanoSecondRequest(Request):
    @classmethod
    def generate_id(*_):
        return time.time_ns()

app = Sanic(..., request_class=NanoSecondRequest)

@app.get("/")
async def handler(request):
    return text(str(request.id))

小技巧

重要的是要记住,你传递的是类而不是类的实例。

定制请求对象#

可以创建 sanic.request.Request 的子类来为请求对象添加额外的功能。这对于添加特定于你的应用程序的额外属性或方法非常有用。

例如,想象你的应用程序发送包含用户 ID 的自定义头。你可以创建自定义请求对象,它将解析该头并为你存储用户 ID。

from sanic import Sanic, Request

class CustomRequest(Request):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.user_id = self.headers.get("X-User-ID")

现在,在你的处理程序中,你可以访问 user_id 属性。

@app.route("/")
async def handler(request: CustomRequest):
    return text(f"User ID: {request.user_id}")