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)

     

     

     

      

      

      

      

      

  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/golangav/p/8254097.html
Copyright © 2011-2022 走看看