flask项目一启动,有6个全局变量
_request_ctx_stack:LocalStack #LocalStack对象
_app_ctx_stack:LocalStack #LocalStack对象
current_app:LocalProxy(_find_app)
request:LocalProxy #LocalStack对象
session:LocalProxy #LocalStack对象
g:LocalProxy #LocalStack对象
请求来了
app.__call__()
----->内部执行:self.wsgi_app(environ, start_response)
wsgi_app()
1.执行:ctx = self.request_context(environ):返回一个RequestContext对象,并且封装了request(当次请求的request对象),session。
2.执行:ctx.push():RequestContext对象的push方法
2.1 push方法中中间位置382行有:_request_ctx_stack.push(self),self指的是ctx对象
2.2 去_request_ctx_stack对象的类中找push方法(LocalStack中找push方法)
2.3 push源码
def push(self, obj):
# 通过反射找到self._local,在__init__实例化的时候生成的:self._local = Local()
# Local() flask封装了支持线程和协程的local对象
# 一开始取不到stack,返回None
rv = getattr(self._local, "stack", None)
if rv is None:
# 走到这,self._local.stack = [],rv = []
self._local.stack = rv = []
# 把ctx放到列表中
# self._local={'线程id1':{'stack':[ctx,]},'线程id2':{'stack':[ctx,]},'线程id3':{'stack':[ctx,]}}
rv.append(obj)
return rv
如果在视图函数中使用request对象,比如:print(request)
1.会调用request对象的`__str__`方法,request类是:LocalProxy
2.LocalProxy中的`__str__`方法:lambda x: str(x._get_current_object())
1.内部执行_get_current_object()方法的源码如下:
def _get_current_object(self):
if not hasattr(self.__local, "__release_local__"):
# self.__local()在__init__的时候,实例化的,在__init__中:object.__setattr__(self, "_LocalProxy__local", local)
# 用了隐藏属性
# self.__loacl
# 实例化该类的时候传入的local(偏函数的内存地址:request = LocalProxy(partial(_lookup_req_object, "request")))
# 加括号返回,就会执行偏函数,也就是执行_lookup_req_object,不需要传参数了
# 这个地方的返回值就是request对象(当次请求的request,没有乱)
return self.__local()
try:
return getattr(self.__local, self.__name__)
except AttributeError:
raise RuntimeError("no object bound to %s" % self.__name__)
3._lookup_req_object函数源码如下:
def _lookup_req_object(name):
# name就是'request'字符串
# top方法是把第二步中放入的ctx取出来,因为都在一个线程内,当前取到的就是当前请求的ctx对象
top = _request_ctx_stack.top
if top is None:
raise RuntimeError(_request_ctx_err_msg)
# 通过反射,去ctx中把request对象返回
return getattr(top, name)
4.所以:print(request)实质上是在打印当次请求的request对象的__str__
如果在视图函数中使用request对象
比如:print(request.method):实质上是取到当次请求的request对象的methid属性
最终,请求结束执行
ctx.auto_pop(error)# 把ctx移除掉
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Sdcb Chats 技术博客:数据库 ID 选型的曲折之路 - 从 Guid 到自增 ID,再到
· 语音处理 开源项目 EchoSharp
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 使用 Dify + LLM 构建精确任务处理应用