Flask框架 —— session源码分析

目录

  • session源码分析

    • 1、请求来了,执行__call__方法
    • 2、__call__方法
    • 3、调用__call__方法
      • 3.1、ctx = self.request_context(environ) --- 得到空的session
      • 3.2、ctx.push() --- 调用open_session方法
      • 3.3、self.full_dispatch_request() --- 路由分发,执行函数,写入session

session源码分析

1、请求来了,执行__call__方法

# 请求来了执行 __call__方法
if __name__ == ‘__main__‘:
    app.__call__
    app.run()

2、__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."""
    return self.wsgi_app(environ, start_response)

3、调用__call__方法

    def wsgi_app(self, environ, start_response):
        # 1.得到request,和空的session
        # ctx是RequestContext的对象,对象里面有空的session和request
        ctx = self.request_context(environ)
        error = None
        try:
            try:
                # 2.从request中的cookie中取出value,解密过转成session对象 --> open_session
                ctx.push()
                # 3.路由映射到函数,执行函数,然后保存session --> save_session,请求结束
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.handle_exception(e)
            except:
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
            

3.1、ctx = self.request_context(environ) --- 得到空的session

    # 1. 获得RequestContext对象 ---> ctx
    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)     # request_class = Request
            self.request = request
            self.url_adapter = app.create_url_adapter(self.request)
            self.flashes = None
            self.session = None
            

3.2、ctx.push() --- 调用open_session方法

    # 2.ctx.push() --- 调用open_session方法
    def push(self):
        """Binds the request context to the current context."""
        top = _request_ctx_stack.top
        if top is not None and top.preserved:
            top.pop(top._preserved_exc)

        # Before we push the request context we have to ensure that there
        # is an application context.
        app_ctx = _app_ctx_stack.top
        if app_ctx is None or app_ctx.app != self.app:
            app_ctx = self.app.app_context()
            app_ctx.push()
            self._implicit_app_ctx_stack.append(app_ctx)
        else:
            self._implicit_app_ctx_stack.append(None)

        if hasattr(sys, ‘exc_clear‘):
            sys.exc_clear()

        _request_ctx_stack.push(self)

        # Open the session at the moment that the request context is available.
        # This allows a custom open_session method to use the request context.
        # Only open a new session if this is the first time the request was
        # pushed, otherwise stream_with_context loses the session.

        # 从request中的cookie中取出value,(有解密过程)转成session对象
        # 正常情况下此时session中有值了
        # 如果request中没有cookie,那么session中仍然没有值
        if self.session is None:
            # session_interface = SecureCookieSessionInterface()
            session_interface = self.app.session_interface
            # 2.1 opensession(),SecureCookieSessionInterface类中
            self.session = session_interface.open_session(
                self.app, self.request
            )

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

3.2.1、session_interface.open_session() --- 从通过session的名字取出cookie的值转成session

# 2.1.session_interface.open_session()
class SecureCookieSessionInterface(SessionInterface):
    def open_session(self, app, request):
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        # 通过session的名字取出cookie的值,key:value形式,得到的是json格式的字符串
        val = request.cookies.get(app.session_cookie_name)
        if not val:
            return self.session_class()
        max_age = total_seconds(app.permanent_session_lifetime)
        try:
            # 将json格式字符串转成字典
            data = s.loads(val, max_age=max_age)
            # 返回一个特殊的字典
            return self.session_class(data)
        except BadSignature:
            return self.session_class()
        

3.3、self.full_dispatch_request() --- 路由分发,执行函数,写入session

# 3.self.full_dispatch_request()
    1 执行before_request
    2 执行视图函数
    3 把session写入
        if not self.session_interface.is_null_session(ctx.session):
            self.session_interface.save_session(self, ctx.session, response)

    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)
        # 3.1 把session保存写入cookie
        return self.finalize_request(rv)
    

3.3.1、self.finalize_request(rv) --- 调用save_session()保存写入session

# 3.1.self.finalize_request(rv)
    def finalize_request(self, rv, from_error_handler=False):
        response = self.make_response(rv)
        try:
            # 利用save_session 保存写入session
            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
    
3.3.1.1、self.process_response(response) --- 调用save_session方法
# 保存写入session
    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方法保存写入session
            self.session_interface.save_session(self, ctx.session, response)
        return response
    
save_session()方法
class SecureCookieSessionInterface(SessionInterface):
    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)
        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
        )

原文地址:https://www.cnblogs.com/linagcheng/p/10401741.html

时间: 2024-08-29 00:18:47

Flask框架 —— session源码分析的相关文章

Flask中session源码执行过程

1.面向对象补充知识metaclass 创建类就可以有两种方式: a.普通方式 1 class Foo(object): 2 3 def func(self): 4 print 'hello wupeiqi' b.特殊方式(type类的构造函数) 1 def func(self): 2 print 'hello wupeiqi' 3 4 Foo = type('Foo',(object,), {'func': func}) 5 #type第一个参数:类名 6 #type第二个参数:当前类的基类

Android异步任务处理框架AsyncTask源码分析

[转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比如最常见的网络请求).遇到这种问题,我们可以自己通过Handler+Message+Thread/ThreadPool来构造一个异步耗时任务框架.当你下次项目中又遇到一个网络请求,你又不得不重写异步耗时任务处理框架.出于避免开发者重复搬砖工作,Google工程师给开发者搭建了一个通用的异步耗时任务处理框架--AsyncTask. Asyn

skynet 框架snax源码分析1---变量注入

skynet为了简化服务的编写,推出了snax框架,源码里也有一个例子pingserver.这是snax原创文章的第一篇,所以先就分析snax框架里的interface.lua源码,它的实现应用了一个闭包中的upvalue注入技巧. 凡是框架都得遵循框架的约定,snax有两个大的约定,一是约定了一组预置的接口init/exit/hotfix:二是accept/response这两组用来编写服务的接口.本文,并不涉及这些,而是谈accept/response是如何注入给snax服务的. snax框

Django——Session源码分析

首先我们导入django.contrib.sessions.middleware这个中间件,查看里面的Session源码 from django.contrib.sessions.middleware import SessionMiddleware 我们可以看到一个类,可以把他分为3部分: class SessionMiddleware(MiddlewareMixin): def __init__(self, get_response=None): ... def process_reques

Django框架 --CBV源码分析、restful规范、restframework框架

一.CBV源码分析 1.url层的使用CBV from app01 import views url(r'book/',views.Book.as_view()) 2.as_view方法 as_view是一个类方法,实际上是一个闭包函数(内层函数包含对外层作用域的使用) 请求来了以后,调用as_view方法,调用函数中的view方法,view方法是调用了dispatch方法 @classonlymethod def as_view(cls, **initkwargs): def view(req

Android 轻量级ORM数据库开源框架ActiveAndroid 源码分析

ActiveAndroid 项目地址在https://github.com/pardom/ActiveAndroid 关于他的详细介绍和使用步骤 可以看下面两篇文章: https://github.com/pardom/ActiveAndroid/wiki http://www.future-processing.pl/blog/persist-your-data-activeandroid-and-parse/ 请确保你在阅读本文下面的内容之前 熟读上面的2篇文章.我不会再讲一遍如何使用这个框

Flask之wtforms源码分析

一.wtforms源码流程 1.实例化流程分析 1 # 源码流程 2 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._wtforms_meta中 3 2. 执行构造方法 4 5 a. 循环cls._unbound_fields中的字段,并执行字段的bind方法,然后将返回值添加到 self._fields[name] 中. 6 即: 7 _fields = { 8 name: wtforms.fields.

框架-springmvc源码分析

参考: http://www.cnblogs.com/heavenyes/p/3905844.html#a1 springmvc是一个基于spring的web框架.本篇文章对它的工作原理以及源码进行深入分析. 一.springmvc请求处理流程 二.springmvc的工作机制 三.springmvc核心源码分析 四.谈谈springmvc的优化 一.springmvc请求处理流程 引用spring in action上的一张图来说明了springmvc的核心组件和请求处理流程: ①:Dispa

一步步搭建自己的轻量级MVCphp框架-(三)一个国产轻量级框架Amysql源码分析(2) 进程

Amysql类 按照我的理解这就是框架的初始化 上代码 class Amysql { public $AmysqlProcess; public function Amysql() { global $Config; ini_set("magic_quotes_runtime", false); ($Config['DebugPhp'] && error_reporting(E_ALL)) || error_reporting(0); // 是否报错 ($Config[