fastapi中的请求上下文

背景

fastapi专注于异步、中间件和依赖项的处理,无法在任意地方使用请求上下文。而Flask中,较为明显的优点,便是可以随处使用请求上下文还有对象g。

构造g对象

  • 原理:基于contextvars来管理上下文

  • 代码:

    点击查看代码
    from contextvars import ContextVar, Token
    from typing import Any, Dict
    
    from starlette.types import ASGIApp, Receive, Scope, Send
    
    
    class Globals:
        __slots__ = ("_vars", "_reset_tokens")
    
        _vars: Dict[str, ContextVar]
        _reset_tokens: Dict[str, Token]
    
        def __init__(self) -> None:
            object.__setattr__(self, "_vars", {})
            object.__setattr__(self, "_reset_tokens", {})
    
        def reset(self) -> None:
            for _name, var in self._vars.items():
                try:
                    var.reset(self._reset_tokens[_name])
                # ValueError will be thrown if the reset() happens in
                # a different context compared to the original set().
                # Then just set to None for this new context.
                except ValueError:
                    var.set(None)
    
        def _ensure_var(self, item: str) -> None:
            if item not in self._vars:
                self._vars[item] = ContextVar(f"globals:{item}", default=None)
                self._reset_tokens[item] = self._vars[item].set(None)
    
        def __getattr__(self, item: str) -> Any:
            return self._vars[item].get()
    
        def __setattr__(self, item: str, value: Any) -> None:
            self._ensure_var(item)
            self._vars[item].set(value)
    
    
    class GlobalsMiddleware:
        def __init__(self, app: ASGIApp) -> None:
            self.app = app
    
        async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
            if scope["type"] != "lifespan":
                g.reset()
            await self.app(scope, receive, send)
    
    
    g = Globals()
    

【注】:代码来源

posted @ 2022-06-28 22:12  F___Q  阅读(726)  评论(0)    收藏  举报