Flask请求上下文
# 说实话,当时看完视频知道怎么回事。就是容易忘.....
# 不过总不能一直看视频对吧,尽快理解和掌握吧....惭愧啊
预备知识
1. werkzeug
当我们下载flask模块时该模块也会被下载,那么该模块有什么用处呢?
我们看下面的代码
from werkzeug.wrappers import Response, Request
from werkzeug.serving import run_simple
@Request.application
def app(req):
print(req)
print(req.method)
print(req.path)
return Response("200 OK!")
run_simple(hostname="127.0.0.1", port=8800, application=app)
-
看运行结果
-
是不是很好奇?它怎么会有request对象
这些我们暂且不讨论,当我们运行run_simple时,是不是相当于执行了app函数 ---> app() (可能你不知道现在在干什么,往下看)
2. 线程安全
.....
3. partial
-
偏函数
-
示例
from functools import partial def ab(a, b): print(a) return a + b # 第一个参数为对象,后面可以指定参数: a=1, b=2 new_ab = partial(ab, a = "request", b="200 OK!") new_ab = partial(ab, "request") # 指定后就不需要再传参了 # print(new_ab()) print(new_ab("200 OK!"))
请求上下文
1. 请求上文
-
flask实例
from flask import Flask, request app = Flask(__name__) @app.route("/") def index(): return "123" if __name__ == '__main__': app.run() # 进去看run源码
-
run方法
.....省略..... from werkzeug.serving import run_simple # 熟悉吧,就刚刚的 # 我们就可以继续引申我们的flask的app实例运行时,也可以说是这样执行了app实例:通过对象()方式执行 try: # flask实例也是通过run_simple运行起来的,也就是说执行时是 flask实例+()执行 # 但实例+()怎么执行呢? __call__方法啊。想起来了不 run_simple(host, port, self, **options) finally: self._got_first_request = False
-
也就是说,flask实例执行__call__方法 from flask import Flask, request app = Flask(__name__) @app.route("/") def index(): return "123" if __name__ == '__main__': app.run() # 进去看run源码 app.__call__ # 继续进去看源码
-
call方法
def __call__(self, environ, start_response): # self = app = Flask(), environ为请求原始信息 """The WSGI server calls the Flask application object as the WSGI application. This calls :meth:`wsgi_app` which can be wrapped to applying middleware.""" return self.wsgi_app(environ, start_response)
-
wsgi_app方法
def wsgi_app(self, environ, start_response): self = app = Flask() # 最终返回一个RequestContext(),含有request、session属性(从environ --> 请求原始信息中取出的) ctx = self.request_context(environ) # ctx = RequestContext(..) ctx含有request、session属性 error = None try: try: ctx.push() # request_context.push() ..... 省略 ....
-
继续看ctx.push()
def push(self): # self = ctx = RequestContext() = (request,session) top = _request_ctx_stack.top # 这里先直接过,是None # 不执行 if top is not None and top.preserved: top.pop(top._preserved_exc) ..... 省略 .... _request_ctx_stack.push(self) # self = ctx(request,session)
-
看 request_ctx_stack.push(self),我们要先知道 request_ctx_stack
_request_ctx_stack = LocalStack() # 将该类进行实例化
def __init__(self): self._local = Local() # 继续实例化Local
class Local(object): __slots__ = ("__storage__", "__ident_func__") def __init__(self): # 设置属性 object.__setattr__(self, "__storage__", {}) # get_ident是一个函数,是为了获取线程id,看预备知识 object.__setattr__(self, "__ident_func__", get_ident) # 线程id # Local = {"__storage__":{},"__ident_func__":get_ident} 是一个对象(就是为了看起来方便,不是一个字典)
-
最终也就是说
_request_ctx_stack = LocalStack() # LocalStack()该实例化属性含有_local属性 # _local = {"__storage__":{},"__ident_func__":get_ident} _request_ctx_stack = LocalStack() --> # ._local >>> {"__storage__":{},"__ident_func__":get_ident}
-
继续回到_request_ctx_stack.push(self),看push方法
def push(self, obj): # obj = ctx = (request,session), self = _request_ctx_stack = LocalStack() # _local >>> {"__storage__":{},"__ident_func__":get_ident} rv = getattr(self._local, "stack", None) if rv is None: self._local.stack = rv = [] # .stack = xx,没有该属性,执行setattr方法 # 可能涉及拷贝,对rv操作就对字典中的[]也进行了操作 rv.append(obj) # {"__storage__":{9527:{stack:[ctx(request,session)]}},"__ident_func__":get_ident} return rv # {9527:{"stack":[ctx(request,session)]}}
def __setattr__(self, name, value): # name = stack, value = [] ident = self.__ident_func__() # 获取线程id,假设为9527 storage = self.__storage__ # 获取到一个 空{} try: storage[ident][name] = value # storage = {ident:} except KeyError: storage[ident] = {name: value} # storage = {9527:{"stack:[]}}
-
2. 请求下文
-
需要用到上面的
partial
-
flask实例
from flask import Flask, request app = Flask(__name__) @app.route("/") def index(): print(request) # 点进去看源码 print(request.method) return "123" if __name__ == '__main__': app.run() # 进去看run源码
-
request:
request = LocalProxy(partial(_lookup_req_object, "request")) # 将request作为参数传入
-
_lookup_req_object
def _lookup_req_object(name): # name = request # 这里省了一点步骤,你可以继续点进top,记得有时候需要getattr或者setattr top = _request_ctx_stack.top # _request_ctx_stack = [ctx(request,session)] # top = ctx(request,session) = RequestContext(),里面含有request、session等属性 if top is None: raise RuntimeError(_request_ctx_err_msg) # 从ctx获取request属性 return getattr(top, name)
-
该偏函数执行后返回一个request对象(该对象就是request自身)
-
-
从request获取属性,例如method
request.method # 没有该属性,执行LocalProxy中的__gatattr__方法,先进行实例化再执行__gatattr__方法 request = LocalProxy(partial(_lookup_req_object, "request")) # 将request作为参数传入
-
实例化
def __init__(self, local, name=None): # local就是偏函数partial,偏函数执行可以获取request真身 object.__setattr__(self, "_LocalProxy__local", local) object.__setattr__(self, "__name__", name) # 判断该偏函数是否可以执行和是否不含有__release_local__属性,成立!!! if callable(local) and not hasattr(local, "__release_local__"): object.__setattr__(self, "__wrapped__", local) # 设置属性
-
执行__gatattr__方法
def __getattr__(self, name): # name = method, form ... if name == "__members__": return dir(self._get_current_object()) # 从某个对象中执行getattr方法,执行self._get_current_object()方法获取对象 return getattr(self._get_current_object(), name)
-
执行_get_current_object()方法
def _get_current_object(self): # 看实例化:object.__setattr__(self, "_LocalProxy__local", local),设置类的私有属性值 if not hasattr(self.__local, "__release_local__"): # 获取私有属性,该私有属性值为local,也就是偏函数 return self.__local() # 执行偏函数,获取request真身 try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError("no object bound to %s" % self.__name__)
-
结束:
def __getattr__(self, name): # name = method, form ... if name == "__members__": return dir(self._get_current_object()) # 从某个对象中执行getattr方法,执行self._get_current_object()方法获取对象 return getattr(self._get_current_object(), name) # 从request中获取method等属性