Flask框架(五) —— session源码分析

session源码分析

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

  1. # 请求来了执行 __call__方法
  2. if __name__ == '__main__':
  3. app.__call__
  4. app.run()

2、__call__方法

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

3、调用__call__方法

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

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

  1. # 1. 获得RequestContext对象 ---> ctx
  2. def request_context(self, environ):
  3. return RequestContext(self, environ)
  4. class RequestContext(object):
  5. def __init__(self, app, environ, request=None):
  6. self.app = app
  7. if request is None:
  8. request = app.request_class(environ) # request_class = Request
  9. self.request = request
  10. self.url_adapter = app.create_url_adapter(self.request)
  11. self.flashes = None
  12. self.session = None

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

  1. # 2.ctx.push() --- 调用open_session方法
  2. def push(self):
  3. """Binds the request context to the current context."""
  4. top = _request_ctx_stack.top
  5. if top is not None and top.preserved:
  6. top.pop(top._preserved_exc)
  7. # Before we push the request context we have to ensure that there
  8. # is an application context.
  9. app_ctx = _app_ctx_stack.top
  10. if app_ctx is None or app_ctx.app != self.app:
  11. app_ctx = self.app.app_context()
  12. app_ctx.push()
  13. self._implicit_app_ctx_stack.append(app_ctx)
  14. else:
  15. self._implicit_app_ctx_stack.append(None)
  16. if hasattr(sys, 'exc_clear'):
  17. sys.exc_clear()
  18. _request_ctx_stack.push(self)
  19. # Open the session at the moment that the request context is available.
  20. # This allows a custom open_session method to use the request context.
  21. # Only open a new session if this is the first time the request was
  22. # pushed, otherwise stream_with_context loses the session.
  23. # 从request中的cookie中取出value,(有解密过程)转成session对象
  24. # 正常情况下此时session中有值了
  25. # 如果request中没有cookie,那么session中仍然没有值
  26. if self.session is None:
  27. # session_interface = SecureCookieSessionInterface()
  28. session_interface = self.app.session_interface
  29. # 2.1 opensession(),SecureCookieSessionInterface类中
  30. self.session = session_interface.open_session(
  31. self.app, self.request
  32. )
  33. if self.session is None:
  34. self.session = session_interface.make_null_session(self.app)

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

  1. # 2.1.session_interface.open_session()
  2. class SecureCookieSessionInterface(SessionInterface):
  3. def open_session(self, app, request):
  4. s = self.get_signing_serializer(app)
  5. if s is None:
  6. return None
  7. # 通过session的名字取出cookie的值,key:value形式,得到的是json格式的字符串
  8. val = request.cookies.get(app.session_cookie_name)
  9. if not val:
  10. return self.session_class()
  11. max_age = total_seconds(app.permanent_session_lifetime)
  12. try:
  13. # 将json格式字符串转成字典
  14. data = s.loads(val, max_age=max_age)
  15. # 返回一个特殊的字典
  16. return self.session_class(data)
  17. except BadSignature:
  18. return self.session_class()

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

  1. # 3.self.full_dispatch_request()
  2. 1 执行before_request
  3. 2 执行视图函数
  4. 3 session写入
  5. if not self.session_interface.is_null_session(ctx.session):
  6. self.session_interface.save_session(self, ctx.session, response)
  7. def full_dispatch_request(self):
  8. self.try_trigger_before_first_request_functions()
  9. try:
  10. request_started.send(self)
  11. rv = self.preprocess_request()
  12. if rv is None:
  13. # 路由分发,执行视图函数
  14. rv = self.dispatch_request()
  15. except Exception as e:
  16. rv = self.handle_user_exception(e)
  17. # 3.1 把session保存写入cookie
  18. return self.finalize_request(rv)

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

  1. # 3.1.self.finalize_request(rv)
  2. def finalize_request(self, rv, from_error_handler=False):
  3. response = self.make_response(rv)
  4. try:
  5. # 利用save_session 保存写入session
  6. response = self.process_response(response)
  7. request_finished.send(self, response=response)
  8. except Exception:
  9. if not from_error_handler:
  10. raise
  11. self.logger.exception('Request finalizing failed with an '
  12. 'error while handling an error')
  13. return response
3.3.1.1、self.process_response(response) --- 调用save_session方法
  1. # 保存写入session
  2. def process_response(self, response):
  3. ctx = _request_ctx_stack.top
  4. bp = ctx.request.blueprint
  5. funcs = ctx._after_request_functions
  6. if bp is not None and bp in self.after_request_funcs:
  7. funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
  8. if None in self.after_request_funcs:
  9. funcs = chain(funcs, reversed(self.after_request_funcs[None]))
  10. for handler in funcs:
  11. response = handler(response)
  12. if not self.session_interface.is_null_session(ctx.session):
  13. # 调用save_session方法保存写入session
  14. self.session_interface.save_session(self, ctx.session, response)
  15. return response
save_session()方法
  1. class SecureCookieSessionInterface(SessionInterface):
  2. def save_session(self, app, session, response):
  3. domain = self.get_cookie_domain(app)
  4. path = self.get_cookie_path(app)
  5. # If the session is modified to be empty, remove the cookie.
  6. # If the session is empty, return without setting the cookie.
  7. if not session:
  8. if session.modified:
  9. response.delete_cookie(
  10. app.session_cookie_name,
  11. domain=domain,
  12. path=path
  13. )
  14. return
  15. # Add a "Vary: Cookie" header if the session was accessed at all.
  16. if session.accessed:
  17. response.vary.add('Cookie')
  18. if not self.should_set_cookie(app, session):
  19. return
  20. httponly = self.get_cookie_httponly(app)
  21. secure = self.get_cookie_secure(app)
  22. samesite = self.get_cookie_samesite(app)
  23. expires = self.get_expiration_time(app, session)
  24. val = self.get_signing_serializer(app).dumps(dict(session))
  25. response.set_cookie(
  26. app.session_cookie_name,
  27. val,
  28. expires=expires,
  29. httponly=httponly,
  30. domain=domain,
  31. path=path,
  32. secure=secure,
  33. samesite=samesite
  34. )
博客内容仅供参考,部分参考他人优秀博文,仅供学习使用

Flask框架(五) —— session源码分析的更多相关文章

  1. Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析

    Flask框架(三)—— 请求扩展.中间件.蓝图.session源码分析 目录 请求扩展.中间件.蓝图.session源码分析 一.请求扩展 1.before_request 2.after_requ ...

  2. DotNetty网络通信框架学习之源码分析

    DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...

  3. 设计模式(十五)——命令模式(Spring框架的JdbcTemplate源码分析)

    1 智能生活项目需求 看一个具体的需求 1) 我们买了一套智能家电,有照明灯.风扇.冰箱.洗衣机,我们只要在手机上安装 app 就可以控制对这些家电工作. 2) 这些智能家电来自不同的厂家,我们不想针 ...

  4. $Django cbv源码分析 djangorestframework框架之APIView源码分析

    1 CBV的源码分析 #视图 class login (View): pass #路由 url(r'^books/$', views.login.as_view()) #阅读源码: #左侧工程栏--- ...

  5. 深入理解分布式调度框架TBSchedule及源码分析

    简介 由于最近工作比较忙,前前后后花了两个月的时间把TBSchedule的源码翻了个底朝天.关于TBSchedule的使用,网上也有很多参考资料,这里不做过多的阐述.本文着重介绍TBSchedule的 ...

  6. Django——Session源码分析

    首先我们导入django.contrib.sessions.middleware这个中间件,查看里面的Session源码 from django.contrib.sessions.middleware ...

  7. 设计模式(二十一)——解释器模式(Spring 框架中SpelExpressionParser源码分析)

    1 四则运算问题 通过解释器模式来实现四则运算,如计算 a+b-c 的值,具体要求 1) 先输入表达式的形式,比如 a+b+c-d+e,  要求表达式的字母不能重复 2) 在分别输入 a ,b, c, ...

  8. Nginx学习笔记(五) 源码分析&内存模块&内存对齐

    Nginx源码分析&内存模块 今天总结了下C语言的内存分配问题,那么就看看Nginx的内存分配相关模型的具体实现.还有内存对齐的内容~~不懂的可以看看~~ src/os/unix/Ngx_al ...

  9. ⑤NuPlayer播放框架之GenericSource源码分析

    [时间:2017-01] [状态:Open] [关键词:android,nuplayer,开源播放器,播放框架,GenericSource] 0 导读 GenericSource是NuPlayer:: ...

随机推荐

  1. spring+mybatis事务配置(转载)

    原文地址:http://blog.csdn.net/wgh1015398431/article/details/52861048 申明式事务配置步骤 .xml文件头部需要添加spring的相关支持: ...

  2. 02/Oct/2019:11:55:28 类型的时间转换为

    public static String upDataTime(String time) { Date upTime = new Date(); String newtime = null; Simp ...

  3. hive中groupby和distinct区别以及性能比较

    Hive去重统计 先说核心: 都会在map阶段count,但reduce阶段,distinct只有一个, group by 可以有多个进行并行聚合,所以group by会快. 经常在公司还能看到.很多 ...

  4. 使用SpringBoot发邮件

    SpringBoot中已有发邮件的工具包,只需要引用即可使用 1,pom引用 <dependency> <groupId>org.springframework.boot< ...

  5. winform 皮肤

    winform  皮肤 https://github.com/kwonganding/winform.controls

  6. 实战build-react(三)

    安装 redux-thunk yarn add redux-thunk 或 npm install redux-thunk --save https://github.com/zalmoxisus/r ...

  7. codevs 1020 孪生蜘蛛 x

    题目描述 Description 在G城保卫战中,超级孪生蜘蛛Phantom001和Phantom002作为第三层防卫被派往守护内城南端一带极为隐秘的通道. 根据防护中心的消息,敌方已经有一只特种飞蛾 ...

  8. 【gym102394L】LRU Algorithm(自然溢出哈希)

    题意:给定一个n个数的数字序列,第i个数为a[i],每次操作会将a[i]插入或移到最前端: 1.若a[i]已经在序列中出现过,则将其移到最前端,并删除原出现位置 2.若a[i]未出现过,则直接将其插入 ...

  9. python build-in function

    目录(?)[-] absx alliterable anyiterable basestring binx boolx callableobject chri classmethodfunction ...

  10. (55)Linux驱动开发之一驱动概述

                                                                                                      驱动 ...