flask的request_context原理 基于flask v0.1
2017-02-27 22:32
399 查看
一来就上代码,问你怕没有
这两段代码显示本文的的重点LocalStack和_RequestContext
先介绍一下_RequestContext,官方文档是这么说的:
接下来,我们就要介绍flask的精髓了,Local,LocalStack和LocalProxy这三个类。
那么LocalStack是用来干嘛的呢。它的作用是将上面的Local().key = value 变成LocalStack().push(value)
通过list来模拟了堆栈的操作。也是基于Local这个类的。但是为什么需要使用栈呢?
那么我们继续看看LocalProxy类。代理模式就不多说了,一种设计模式。我们看看代码:
由上面可以知道我们需要访问的request属性是在_requestContext()里面。那么访问request的时候只能_request_ctx_stack.top.request了。这样子写法没有问题,就是缺少了点优雅。那么如果直接request=_request_ctx_stack.top.request呢。这肯定是不行的,因为在多线程的环境下,request是需要根据当前环境来获得对应的值,这样写相当于写死了request的值了。那么LocalProxy是怎么做的呢?当对LocalProxy属性进行访问的时候,它都会执行一次_get_current_object函数,该函数就是执行我们传入的函数得到访问对象,比如上面的lambda函数就是得到_request_ctx_context.top.request对象。最后再对得到的对象进行属性访问。这样子就可以很优雅地实现了动态获取当前线程的request对象了。高,实在是高!
到这里,其实是很清晰这整个过程了。为什么其实在多线程环境下,request对象是根据当前环境取得的值。
参考博文:
flask request g session的实现原理
werkzeug源码分析(local.py
_request_ctx_stack = LocalStack() current_app = LocalProxy(lambda: _request_ctx_stack.top.app) request = LocalProxy(lambda: _request_ctx_stack.top.request) session = LocalProxy(lambda: _request_ctx_stack.top.session) g = LocalProxy(lambda: _request_ctx_stack.top.g)
class _RequestContext(object): def __init__(self, app, environ): self.app = app self.url_adapter = app.url_map.bind_to_environ(environ) self.request = app.request_class(environ) self.session = app.open_session(self.request) self.g = _RequestGlobals() self.flashes = None def __enter__(self): _request_ctx_stack.push(self) def __exit__(self, exc_type, exc_value, tb): if tb is None or not self.app.debug: _request_ctx_stack.pop()
这两段代码显示本文的的重点LocalStack和_RequestContext
先介绍一下_RequestContext,官方文档是这么说的:
""" The request context contains all request relevant information. It is created at the beginning of the request and pushed to the `_request_ctx_stack` and removed at the end of it. It will create the URL adapter and request object for the WSGI environment provided. """简单地说,就是_RequestContext是保留一个request过程中所有的相关信息,如 url adapter和WSGI environment等。app会在处理一个request前将request的相关信息压到_request_ctx_stack栈顶,等到处理完这个request的时候将它弹出。所以回过头来看代码
current_app = LocalProxy(lambda: _request_ctx_stack.top.app) request = LocalProxy(lambda: _request_ctx_stack.top.request)当我们访问flask.request的时候,其实是访问_request_ctx_stack.top这个对象里面的request属性。_request_ctx_stack.top自然就是栈顶了,那么栈顶是什么样一个对象呢?对了,就是刚才介绍的_RequestContext对象了,它在dispatch_request的之前就压入。这个_RequestContext对象里面有request这个属性。所以flask.request其实就是_RequestContext.request。
接下来,我们就要介绍flask的精髓了,Local,LocalStack和LocalProxy这三个类。
class Local(object): __slots__ = ('__storage__', '__ident_func__') def __init__(self): object.__setattr__(self, '__storage__', {}) object.__setattr__(self, '__ident_func__', get_ident) def __getattr__(self, name): try: return self.__storage__[self.__ident_func__()][name] except KeyError: raise AttributeError(name)这个Local类的核心是__ident_func__()函数,这个函数保证了即使在多线程环境下,保存在Local里面的变量不会混乱,而且支持greenlet这个异步协程库。
那么LocalStack是用来干嘛的呢。它的作用是将上面的Local().key = value 变成LocalStack().push(value)
通过list来模拟了堆栈的操作。也是基于Local这个类的。但是为什么需要使用栈呢?
class LocalStack(object): def __init__(self): self._local = Local() def push(self, obj): """Pushes a new item to the stack""" rv = getattr(self._local, 'stack', None) if rv is None: self._local.stack = rv = [] rv.append(obj) return rv
那么我们继续看看LocalProxy类。代理模式就不多说了,一种设计模式。我们看看代码:
_request_ctx_stack = LocalStack() _request_ctx_stack.push(_RequestContext())
由上面可以知道我们需要访问的request属性是在_requestContext()里面。那么访问request的时候只能_request_ctx_stack.top.request了。这样子写法没有问题,就是缺少了点优雅。那么如果直接request=_request_ctx_stack.top.request呢。这肯定是不行的,因为在多线程的环境下,request是需要根据当前环境来获得对应的值,这样写相当于写死了request的值了。那么LocalProxy是怎么做的呢?当对LocalProxy属性进行访问的时候,它都会执行一次_get_current_object函数,该函数就是执行我们传入的函数得到访问对象,比如上面的lambda函数就是得到_request_ctx_context.top.request对象。最后再对得到的对象进行属性访问。这样子就可以很优雅地实现了动态获取当前线程的request对象了。高,实在是高!
class LocalProxy(object): def _get_current_object(self): if not hasattr(self.__local, '__release_local__'): return self.__local() try: return getattr(self.__local, self.__name__) except AttributeError: raise RuntimeError('no object bound to %s' % self.__name__)
到这里,其实是很清晰这整个过程了。为什么其实在多线程环境下,request对象是根据当前环境取得的值。
参考博文:
flask request g session的实现原理
werkzeug源码分析(local.py
相关文章推荐
- flask一次request请求过程 基于tag0.7
- 浅谈Flask 中的 线程局部变量 request 原理
- flask一次request请求过程 基于tag0.1
- flask之源码解读RequestContext(请求上下文)执行流程
- 简单示例 flask-login 基于 request_loader 方法的 token 登录
- flask一次request请求过程 基于tag0.2和0.3
- flask基础之AppContext应用上下文和RequestContext请求上下文(六)
- 基于ARP欺骗的嗅探原理
- 基于XMPP协议的即时通讯工具的客户端实现原理
- 基于IMD的包过滤防火墙原理与实现
- 基于SPI的数据报过滤原理与实现
- 基于request/reply模式的MQ例子
- 基于嗅探原理的原始套接字木马
- [DOC]基于ARP欺骗的嗅探原理
- 基于IMD的包过滤防火墙原理与实现
- 基于SPI的数据报过滤原理与实现
- 基于SPI的数据报过滤原理与实现
- 基于SPI的数据报过滤原理与实现
- 基于P2P思想的QQ蠕虫的原理与防治
- 基于ARP欺骗的嗅探原理