zoukankan      html  css  js  c++  java
  • flask0.1版本源码浅析——请求上下文

    说先flask应用在请求时会调用 wsgi_app(self, environ, start_response) 这个方法

        def wsgi_app(self, environ, start_response):
            # ...
            with self.request_context(environ):
                rv = self.preprocess_request()
                if rv is None:
                    rv = self.dispatch_request()
                response = self.make_response(rv)
                response = self.process_response(response)
                return response(environ, start_response)

    这个函数的基本步骤是:

    1. 先是 打开request_context(environ), 然后我们就有了我们需要的“全局request”
    2. 然后preprocess_request()是处理数据前的准备
    3. 接下来调用dispatch_request()方法,这个方法会根据URL匹配的情况调用相关的视图函数
    4. 之后调用response(environ, start_response)方法将响应发送回WSGI服务器
    5. 最后with语句结束,当前线程会被销毁

    request_context 

    可以看出,requests_context 方法会调用 _RequestContext(self, environ) 类, 所以我们看这个类就可以

        def request_context(self, environ):
            """Creates a request context from the given environment and binds
            it to the current context.  This must be used in combination with
            the `with` statement because the request is only bound to the
            current context for the duration of the `with` block.
    
            :params environ: a WSGI environment
            """
            return _RequestContext(self, environ)

    _RequestContext(self, environ)

    class _RequestContext(object):
        """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.
        """
    
        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):
            # do not pop the request stack if we are in debug mode and an
            # exception happened.  This will allow the debugger to still
            # access the request object in the interactive shell.
            if tb is None or not self.app.debug:
                _request_ctx_stack.pop()

    其中对该类的属性:

    • app —— 属于当前Flask应用
    • url_adapter —— 创建一个 Map 实例,为了注册路由使用
    • request —— 接收 environ 后创建了 Request 的实例,储存请求信息
    • session —— 接收 request 信息后,创建Session的相关对象,储存会话信息
    • g —— 存储全局变量
    • flash —— 消息闪现

    _request_ctx_stack

    _request_ctx_stack = LocalStack()

    _request_ctx_stack 是由 LocalStack 类实现的类似栈的结构。

    我们通过 push(self) 可以看出,_request_ctx_stackrequest_context 存储到里面。存储结构为

    {14272: {'stack': [<RequestContext 'http://localhost/' [GET] of test5>]}, 16696: {'stack': [<RequestContext 'http://localhost/' [GET] of test5>]}, 16856: {'stack': [<RequestContext 'http://localhost/' [GET] of test5>]}}

    测试的代码为

    from flask import Flask, _request_ctx_stack
    import threading
    
    app = Flask(__name__)
    
    print _request_ctx_stack._local.__storage__
    
    
    def foo():
        request_context = app.test_request_context()
        _request_ctx_stack.push(request_context)
    
    
    q = []
    
    for i in range(3):
        t = threading.Thread(target=foo)
        t.start()
        q.append(t)
    
    for j in q:
        j.join()
    View Code

    这是一个字典形式的结构,键代表当前线程的数值,值代表当前线程存储的变量,这样很容易实现线程分离,从而使每个线程都可访问自己的内的“全局变量”

    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)

    LocalProxyi是一个 local对象的代理,负责把所有对自己的操作转发给内部的 Local 对象。

    我们可以看出,current_apprequestsessiong 都会是自己线程内的“全局变量”

    with

    这里的 __enter____exit__ 方法是为了 wsgi_app 内 with 语句调用

      

    延伸

    flask0.9版本中加入了应用上下文的概念

  • 相关阅读:
    Numpy存字符串
    一个类似于postman的协议测试工具
    freetds设置超时
    学习jQuery
    webpy 使用python3开发
    gdb调试coredump文件
    htop和ncdu
    rqalpha-自动量化交易系统(一)
    perl学习-运算符添加引号
    xss 和 csrf攻击详解
  • 原文地址:https://www.cnblogs.com/fuzzier/p/7647647.html
Copyright © 2011-2022 走看看