Flask(session)源码详解

 一. session的整个流程:

首先我们Flask启动一般会执行四个步骤

  1. 实例化Flask对象
  2. 设置路由,app里面有一个app.url_map
  3. 启动socket服务端
  4. 请求到来会执行app.__call__方法
from  flask import  Flask


#1. 实例化Flask对象
app = Flask(__name__)


#2. 设置路由
"""
app.url_map = [ 
        ('/login', login)
        ('/home', home)
    ]
"""

@app.route('/index')
def index():
    return 'index'



if __name__ == '__main__':
    #3. 启动socket服务端
    app.run()

    #4. 用户请求到来会执行
    app.__call__
代码

二. 源代码详解:

1、用户请求进来后会执行app.__call__方法:

    def __call__(self, environ, start_response):
        """The WSGI server calls the Flask application object as the
        WSGI application. This calls :meth:`wsgi_app` which can be
        wrapped to applying middleware."""

        #environ 是请求相关的所有数据(由wsgi做了初步的封装)
        #start_respone 是用于设置响应相关的所有数据
        return self.wsgi_app(environ, start_response)

2、执行def wsgi_app(self, environ, start_response)这个函数:

 1     def wsgi_app(self, environ, start_response):
 2         """The actual WSGI application. This is not implemented in
 3         :meth:`__call__` so that middlewares can be applied without
 4         losing a reference to the app object. Instead of doing this::
 5 
 6             app = MyMiddleware(app)
 7 
 8         It's a better idea to do this instead::
 9 
10             app.wsgi_app = MyMiddleware(app.wsgi_app)
11 
12         Then you still have the original application object around and
13         can continue to call methods on it.
14 
15         .. versionchanged:: 0.7
16             Teardown events for the request and app contexts are called
17             even if an unhandled error occurs. Other events may not be
18             called depending on when an error occurs during dispatch.
19             See :ref:`callbacks-and-errors`.
20 
21         :param environ: A WSGI environment.
22         :param start_response: A callable accepting a status code,
23             a list of headers, and an optional exception context to
24             start the response.
25         """
26 
27         """
28         1. 获取environ并对其进行再次封装
29         2. 从environ中获取名称为session的cookie,解密,反序列化。
30         3. 放在一个存数据的地方
31         """
32         # ctx = RequestContext(self,environ) #self就是app对象,environ请求相关原始的数据
33         # ctx.request = app.request_class(environ)
34         ctx = self.request_context(environ)
35         error = None
36         try:
37             try:
38                 #将ctx放到一个存放数据的地方
39                 #执行SecureCookieSessionInterface.open_session,去cookie中获取值并给ctx.session重新赋值
40                 ctx.push()
41                 #4.执行视图函数
42                 response = self.full_dispatch_request()
43             except Exception as e:
44                 error = e
45                 response = self.handle_exception(e)
46             except:
47                 error = sys.exc_info()[1]
48                 raise
49             return response(environ, start_response)
50         finally:
51             if self.should_ignore_error(error):
52                 error = None
53             ctx.auto_pop(error)
54 
55             """
56             1)在某个存数据的地方获取session.加密。序列化=>写入cookie
57 
58             2)然后将存在某个存数据的地方,将它清空
59             """
View Code

2.1此时执行ctx = self.request_context(environ)

这是对请求相关的数据进行再次封装.

3、执行def request_context(self, environ):

这个函数里面 return RequestContext(self, environ)  #返回了一个RequestContext实例化的对象

4、执行class RequestContext(object):

对请求数据进行一些列的封装,并且__init__request方法

class RequestContext(object):
    def __init__(self, app, environ, request=None):
        """
        environ:是请求传过来的数据
        """
        self.app = app
        if request is None:
            #如果request是空则把数据复制给request
            request = app.request_class(environ)
        self.request = request
        self.url_adapter = app.create_url_adapter(self.request)
        self.flashes = None
        #设置session为None
        self.session = None

5、执行def wsgi_app函数下的ctx.push()

1)这里面的操作就是将ctx放到一个存放数据的地方

2)执行SecureCookieSessionInterface.open_session,去cookie中获取值并给ctx.session重新赋值

 6、class RequestContext(object):类下的 def push(self):函数

       #首先判断session是否为None,如果成立则
       if self.session is None:
            #在self.app.session_interface 等于是SecureCookieSessionInterface()实例化的对象
            session_interface = self.app.session_interface
            #然后通过通过session_interface调用SecureCookieSessionInterface下的open_session函数(方法)读取到session
            self.session = session_interface.open_session(
                self.app, self.request
            )

            if self.session is None:
                self.session = session_interface.make_null_session(self.app)

7、执行类class SecureCookieSessionInterface(SessionInterface):

这个类里面包含了对session coooki的操作。def open_session(self, app, request):这个函数是读取session

这个函数def save_session(self, app, session, response):是保存session

7.1执行def open_session(self,app,request):

   def open_session(self, app, request):
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        #读取val这个val就是session的值,session_cookie_name这个就是配置文件的session_cookie_name
        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()

8、执行def wsgi_app(self, environ, start_response):下的函数response = self.full_dispatch_request()

这段代码执行的就是视图函数

9、执行def full_dispatch_request(self):

def full_dispatch_request(self):
    self.try_trigger_before_first_request_functions()
    try:
        request_started.send(self)
        #
        rv = self.preprocess_request()
        if rv is None:
            rv = self.dispatch_request() #调用视图函数
    except Exception as e:
        rv = self.handle_user_exception(e)
    #视图函数执行完毕后,进行善后工作
    return self.finalize_request(rv) 

10、def finalize_request(self, rv, from_error_handler=False):函数

    
def finalize_request(self, rv, from_error_handler=False):
response = self.make_response(rv)
try:
    #执行process_response
    response = self.process_response(response)
    request_finished.send(self, response=response)
except Exception:
    if not from_error_handler:
        raise
    self.logger.exception('Request finalizing failed with an '
                          'error while handling an error')
return response

11、执行def process_response(self, response):

def process_response(self, response):

    ctx = _request_ctx_stack.top
    bp = ctx.request.blueprint
    funcs = ctx._after_request_functions
    if bp is not None and bp in self.after_request_funcs:
        funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
    if None in self.after_request_funcs:
        funcs = chain(funcs, reversed(self.after_request_funcs[None]))
    for handler in funcs:
        response = handler(response)
    if not self.session_interface.is_null_session(ctx.session):
        #这里执行了save_session
        self.session_interface.save_session(self, ctx.session, response)
    return response

 12、执行class SecureCookieSessionInterface(SessionInterface):类下的def save_session(self, app, session, response):函数

    
 def save_session(self, app, session, response):
        domain = self.get_cookie_domain(app)
        path = self.get_cookie_path(app)

        # If the session is modified to be empty, remove the cookie.
        # If the session is empty, return without setting the cookie.
        if not session:
            if session.modified:
                response.delete_cookie(
                    app.session_cookie_name,
                    domain=domain,
                    path=path
                )

            return

        # Add a "Vary: Cookie" header if the session was accessed at all.
        if session.accessed:
            response.vary.add('Cookie')

        if not self.should_set_cookie(app, session):
            return

        httponly = self.get_cookie_httponly(app)
        secure = self.get_cookie_secure(app)
        samesite = self.get_cookie_samesite(app)
        expires = self.get_expiration_time(app, session)
        #对session进行加密,然后dumps编程字符串
        val = self.get_signing_serializer(app).dumps(dict(session))
        #然后在写入用户的浏览器上
        response.set_cookie(
            app.session_cookie_name,
            val,
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite
        )

总结:

其实Flask大致的流程就是:

  1. 实例化Flask对象
  2. 设置路由,app里面有一个app.url_map
  3. 启动socket服务端
  4. 请求到来回执行app.__call__方法
  5. 然后执行wsgi_app方法

      1.获取environ并对其进行再次封装

      2.从environ中获取名称为session的cookie,解密,反序列化。

                     3.放在一个存数据的地方

        4.执行视图函数

                     5.获取某个地方的session加密 =>写入cookie

                     6.存放在某个神奇的位置的相对应的session把它清空

思维导图

       解释:序号1-4是:

     1.获取environ并对其进行再次封装

     2.从environ中获取名称为session的cookie,解密,反序列化。

        3.放在一个存数据的地方

      5-6:   

#将ctx放到一个存放数据的地方
#执行SecureCookieSessionInterface.open_session,去cookie中获取值并给ctx.session重新赋值

      7-10:

#4.执行视图函数
#5.“获取某个地方的session”加密 => 写cookie
posted @ 2018-12-17 09:36  Jacob先生  阅读(534)  评论(0编辑  收藏  举报