zoukankan      html  css  js  c++  java
  • Flask源码分析

    上下文本质 

    - 当请求过来后,将请求相关数据添加到 Local()类中
    	{ 
    		线程或协程唯一标识:{"stack":[request]},
    		线程或协程唯一标识:{"stack":[]},
    		线程或协程唯一标识:{"stack":[]}
    	}
    - 以后使用时 去读取
    - 请求完成之后,将request从列表中移除

    Flask源码

    from flask import Flask,session,request
    
    app = Flask(__name__)
    
    @app.route("/login",methods=["GET","POST"])
    def login():
        return "index"
    
    if __name__ == '__main__':
        #app.__call__()
        app.run()

    1. 执行app.__call__方法

    def __call__(self, environ, start_response):
            return self.wsgi_app(environ, start_response)

    2. 执行wsgi_app方法

    def wsgi_app(self, environ, start_response):
    
        ctx = self.request_context(environ)
        ctx.push()
    
        response = self.full_dispatch_request()

    2.1 生成RequestContext()对象 封装请求相关的数据(request,session)

    ctx = self.request_context(environ)
    
    def request_context(self, environ):
        return RequestContext(self, environ)
    
    class RequestContext(object):
        def __init__(self, app, environ, request=None):
               self.app = app
               if request is None:
                request = app.request_class(environ)
               self.request = request

    2.2 将用户请求数据封装到Local()类中

    ctx.push()
    def push(self):
    
        from .globals import _request_ctx_stack
    
        #将请求数据封装到Local()类
        _request_ctx_stack.push(self)
    
        #处理session
        self.session = self.app.open_session(self.request)
        if self.session is None:
            self.session = self.app.make_null_session()

    2.2.1 导入 _request_ctx_stack对象  内部会自动生成  { 线程或协程唯一标识:{"stack":[]} } 格式 

    from .globals import _request_ctx_stack
    
    class Local(object):
    
        def __init__(self):
            object.__setattr__(self, '__storage__', {})
            object.__setattr__(self, '__ident_func__', get_ident)
    
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
    
    class LocalStack(object):
    
        def __init__(self):
            self._local = Local()
    
        def push(self, obj):
            rv = getattr(self._local, 'stack', None)
            if rv is None:
                self._local.stack = rv = []
            rv.append(obj)
            return rv
    
    _request_ctx_stack = LocalStack()

    2.2.2 执行_request_ctx_stack对象push方法  触发Local类的__setattr__方法 生成  { 线程或协程唯一标识:{"stack":[ RequestContext对象 ]} }

    _request_ctx_stack.push(self)
    
    class Local(object):
    
        def __setattr__(self, name, value):
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
    
    class LocalStack(object):
    
        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
    
    _request_ctx_stack = LocalStack()

    2.2.3 self.session重新赋值

    RequestContext类的 self.session由none重新赋值为SecureCookieSessionInterface类open_session方法的结果(SecureCookieSession对象)
    	- SecureCookieSession对象 就是一个字典
    
    self.session = self.app.open_session(self.request)
    
    def open_session(self, request):
        return self.session_interface.open_session(self, request)
     
    # 之后这里可以自定义自己类 可以继承SecureCookieSessionInterface类
    session_interface = SecureCookieSessionInterface()
    
    class SecureCookieSessionInterface(SessionInterface):
    
        def open_session(self, app, request):
            s = self.get_signing_serializer(app)
            if s is None:
                return None
    
            # 去cookie中获取session作为key 对应的值(包含了此用户的session数据) 
            val = request.cookies.get(app.session_cookie_name)
            if not val:
                return self.session_class()
            max_age = total_seconds(app.permanent_session_lifetime)
            try:
                data = s.loads(val, max_age=max_age)
                return self.session_class(data)
            except BadSignature:
                return self.session_class()

    3. 之后调用request

    #此时你如果调用request 会执行如下代码
    request = LocalProxy(partial(_lookup_req_object, 'request'))
        _lookup_req_object 获取RequestContext()中用户的请求数据

    4. 执行视图函数

    response = self.full_dispatch_request()
    

    4.1 触发只执行一次的装饰器函数 @before_first_request 

    self.try_trigger_before_first_request_functions()

    4.2 # 触发Flask的信号  需要pip3 install blinker

    request_started.send(self)
    

    4.3 执行特殊装饰器  @before_request

    有返回值 返回用户 
    没有返回值 触发并执行视图函数
    rv = self.preprocess_request()
    if rv is None:
        rv = self.dispatch_request()

    4.4 执行请求之后的装饰器  @after_request  且处理session

    return self.finalize_request(rv)
    
        def finalize_request(self, rv, from_error_handler=False):
    
            response = self.process_response(response)
    
                def process_response(self, response):
    
                    # 处理session
                    if not self.session_interface.is_null_session(ctx.session):
                    self.save_session(ctx.session, response)

     

     

     

      

      

      

      

      

     
     
     
     
     
     
     
     
     
  • 相关阅读:
    当事人在土地征收补偿纠纷中需要收集的证据
    ExtJs学习
    谈谈对于企业级系统架构的理解 转来的
    log4net详细配置 转
    基于RBAC的权限设计3
    当事人在土地征收补偿纠纷中需要收集的证据类型
    权限管理设计2
    SQL 字符串分割
    RBAC原理介绍及kasai使用分析
    权限管理设计1
  • 原文地址:https://www.cnblogs.com/wanghaohao/p/8260341.html
Copyright © 2011-2022 走看看