内置session原理

请求到来

当请求进来之后,先执行Flask对象的 __call__ 方法

def wsgi_app(self, environ, start_response):# 获取请求相关数据,并进行封装和加工ctx = self.request_context(environ)# 将请求消息推送到堆栈中,并执行 open_session方法
        ctx.push()error = Nonetry:try:response = self.full_dispatch_request()except Exception as e:error = eresponse = self.make_response(self.handle_exception(e))return response(environ, start_response)finally:if self.should_ignore_error(error):error = Nonectx.auto_pop(error)def __call__(self, environ, start_response):"""Shortcut for :attr:`wsgi_app`."""return self.wsgi_app(environ, start_response)

 def push(self):top = _request_ctx_stack.topif 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.topif 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)# 调用Flask对象的open_session方法self.session = self.app.open_session(self.request)if self.session is None:self.session = self.app.make_null_session()

 def open_session(self, request):"""Creates or opens a new session.  Default implementation stores allsession data in a signed cookie.  This requires that the:attr:`secret_key` is set.  Instead of overriding this methodwe recommend replacing the :class:`session_interface`.:param request: an instance of :attr:`request_class`."""# self指的是Flask对象,session_interface默认值为SecureCookieSessionInterface()return self.session_interface.open_session(self, request)

由以上源码发现,当接收到用户请求之后,会调用 Flask对象的 session_interface对象的open_session方法,以此来获取一个session对象。

class SecureCookieSessionInterface(SessionInterface):"""The default session interface that stores sessions in signed cookiesthrough the :mod:`itsdangerous` module."""#: the salt that should be applied on top of the secret key for the#: signing of cookie based sessions.salt = 'cookie-session'#: the hash function to use for the signature.  The default is sha1digest_method = staticmethod(hashlib.sha1)#: the name of the itsdangerous supported key derivation.  The default#: is hmac.key_derivation = 'hmac'#: A python serializer for the payload.  The default is a compact#: JSON derived serializer with support for some extra Python types#: such as datetime objects or tuples.serializer = session_json_serializersession_class = SecureCookieSessiondef get_signing_serializer(self, app):if not app.secret_key:return Nonesigner_kwargs = dict(key_derivation=self.key_derivation,digest_method=self.digest_method)return URLSafeTimedSerializer(app.secret_key, salt=self.salt,serializer=self.serializer,signer_kwargs=signer_kwargs)def open_session(self, app, request):# 获取加密相关的类,必须设置app.secret_key,不然s就是Nones = self.get_signing_serializer(app)if s is None:return None# 去Cookie中获取 session 对应的值(该值默认是加密之后的session的值,也可以改造成随机字符串)val = request.cookies.get(app.session_cookie_name)if not val:# 未获取到值,则创建一个空字典(就是flask中用到的session)return self.session_class()max_age = total_seconds(app.permanent_session_lifetime)try:data = s.loads(val, max_age=max_age)# 如果获取到值,则将值放入字典中(就是flask中用到的session)return self.session_class(data)except BadSignature:# 解密失败,则创建一个空字典(就是flask中用到的session)return self.session_class()

上述中 self.session_class 就是创建的一个SecureCookieSession对象,这个类是继承了字典的类,其实就是一个特殊的字典。

class SessionMixin(object):"""Expands a basic dictionary with an accessors that are expectedby Flask extensions and users for the session."""def _get_permanent(self):return self.get('_permanent', False)def _set_permanent(self, value):self['_permanent'] = bool(value)#: this reflects the ``'_permanent'`` key in the dict.permanent = property(_get_permanent, _set_permanent)del _get_permanent, _set_permanent#: some session backends can tell you if a session is new, but that is#: not necessarily guaranteed.  Use with caution.  The default mixin#: implementation just hardcodes ``False`` in.new = False#: for some backends this will always be ``True``, but some backends will#: default this to false and detect changes in the dictionary for as#: long as changes do not happen on mutable structures in the session.#: The default mixin implementation just hardcodes ``True`` in.modified = Trueclass UpdateDictMixin(object):"""Makes dicts call `self.on_update` on modifications... versionadded:: 0.5:private:"""on_update = Nonedef calls_update(name):def oncall(self, *args, **kw):rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)if self.on_update is not None:self.on_update(self)return rvoncall.__name__ = namereturn oncalldef setdefault(self, key, default=None):modified = key not in selfrv = super(UpdateDictMixin, self).setdefault(key, default)if modified and self.on_update is not None:self.on_update(self)return rvdef pop(self, key, default=_missing):modified = key in selfif default is _missing:rv = super(UpdateDictMixin, self).pop(key)else:rv = super(UpdateDictMixin, self).pop(key, default)if modified and self.on_update is not None:self.on_update(self)return rv__setitem__ = calls_update('__setitem__')__delitem__ = calls_update('__delitem__')clear = calls_update('clear')popitem = calls_update('popitem')update = calls_update('update')del calls_updateclass CallbackDict(UpdateDictMixin, dict):"""A dict that calls a function passed every time something is changed.The function is passed the dict instance."""def __init__(self, initial=None, on_update=None):dict.__init__(self, initial or ())self.on_update = on_updatedef __repr__(self):return '<%s %s>' % (self.__class__.__name__,dict.__repr__(self))class SecureCookieSession(CallbackDict, SessionMixin):"""Base class for sessions based on signed cookies."""def __init__(self, initial=None):def on_update(self):self.modified = TrueCallbackDict.__init__(self, initial, on_update)self.modified = False

该字典其实就是继承了字典,并在其基础上定制了一些功能,如

class MyDict(dict):def __init__(self, initial):dict.__init__(self, initial)session = MyDict({'k1': 123})print(session, type(session)) # {'k1': 123} <class '__main__.MyDict'>
session['k2'] = 'v2'
print(session)

所以,Flask的视图函数中在对session进行操作时,其实就是在内存中修改一个字典的数据。

业务处理

设置session

响应内容

响应内容其实就讲数据返回给用户,并且把内容中的session重新保存

def wsgi_app(self, environ, start_response):"""The actual WSGI application.  This is not implemented in`__call__` so that middlewares can be applied without losing areference to the class.  So instead of doing this::app = MyMiddleware(app)It's a better idea to do this instead::app.wsgi_app = MyMiddleware(app.wsgi_app)Then you still have the original application object around andcan continue to call methods on it... versionchanged:: 0.7The behavior of the before and after request callbacks was changedunder error conditions and a new callback was added that willalways execute at the end of the request, independent on if anerror occurred or not.  See :ref:`callbacks-and-errors`.:param environ: a WSGI environment:param start_response: a callable accepting a status code,a list of headers and an optionalexception context to start the response"""ctx = self.request_context(environ)ctx.push()error = Nonetry:try:# 处理业务请求,并获取返回值response = self.full_dispatch_request()except Exception as e:error = eresponse = self.make_response(self.handle_exception(e))return response(environ, start_response)finally:if self.should_ignore_error(error):error = Nonectx.auto_pop(error)

 def full_dispatch_request(self):"""Dispatches the request and on top of that performs requestpre and postprocessing as well as HTTP exception catching anderror handling... versionadded:: 0.7"""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)response = self.make_response(rv)# 处理响应内容response = self.process_response(response)request_finished.send(self, response=response)return response

def process_response(self, response):"""Can be overridden in order to modify the response objectbefore it's sent to the WSGI server.  By default this willcall all the :meth:`after_request` decorated functions... versionchanged:: 0.5As of Flask 0.5 the functions registered for after requestexecution are called in reverse order of registration.:param response: a :attr:`response_class` object.:return: a new response object or the same, has to be aninstance of :attr:`response_class`."""ctx = _request_ctx_stack.topbp = ctx.request.blueprintfuncs = ctx._after_request_functionsif 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):# 执行flask对象的save_session方法
            self.save_session(ctx.session, response)return responsedef save_session(self, session, response):"""Saves the session if it needs updates.  For the defaultimplementation, check :meth:`open_session`.  Instead of overriding thismethod we recommend replacing the :class:`session_interface`.:param session: the session to be saved (a:class:`~werkzeug.contrib.securecookie.SecureCookie`object):param response: an instance of :attr:`response_class`"""# 执行session_interface的save_session方法,将内存中的session保存。return self.session_interface.save_session(self, session, response)

执行xxx的save_session方法,将内存中的数据保存。

class SecureCookieSessionInterface(SessionInterface):"""The default session interface that stores sessions in signed cookiesthrough the :mod:`itsdangerous` module."""#: the salt that should be applied on top of the secret key for the#: signing of cookie based sessions.salt = 'cookie-session'#: the hash function to use for the signature.  The default is sha1digest_method = staticmethod(hashlib.sha1)#: the name of the itsdangerous supported key derivation.  The default#: is hmac.key_derivation = 'hmac'#: A python serializer for the payload.  The default is a compact#: JSON derived serializer with support for some extra Python types#: such as datetime objects or tuples.serializer = session_json_serializersession_class = SecureCookieSessiondef get_signing_serializer(self, app):if not app.secret_key:return Nonesigner_kwargs = dict(key_derivation=self.key_derivation,digest_method=self.digest_method)return URLSafeTimedSerializer(app.secret_key, salt=self.salt,serializer=self.serializer,signer_kwargs=signer_kwargs)def open_session(self, app, request):s = self.get_signing_serializer(app)if s is None:return Noneval = 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()def save_session(self, app, session, response):domain = self.get_cookie_domain(app)path = self.get_cookie_path(app)# Delete case.  If there is no session we bail early.# If the session was modified to be empty we remove the# whole cookie.if not session:if session.modified:response.delete_cookie(app.session_cookie_name,domain=domain, path=path)return# Modification case.  There are upsides and downsides to# emitting a set-cookie header each request.  The behavior# is controlled by the :meth:`should_set_cookie` method# which performs a quick check to figure out if the cookie# should be set or not.  This is controlled by the# SESSION_REFRESH_EACH_REQUEST config flag as well as# the permanent flag on the session itself.if not self.should_set_cookie(app, session):returnhttponly = self.get_cookie_httponly(app)secure = self.get_cookie_secure(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)

转载于:https://www.cnblogs.com/ctztake/p/8260887.html

flask内置session原理相关推荐

  1. python构造callable_Python callable内置函数原理解析

    python内置函数 callable用于检查一个对象是否是可调用的,如果函数返回True,object 仍然可能调用失败:但如果返回 False,调用对象 object 绝对不会成功. 一.call ...

  2. 老男孩python全栈9期全套视频_[全套视频] 老男孩Python全栈7期:Flask全套组件及原理剖析视频教程,全套视频教程学习资料通过百度云网盘下载...

    目录├─1398 T* * I K, E% T│ ├─01 python fullstack s7day139 课前分享之找一个对标的人.mp4│ ├─02 python fullstack s7da ...

  3. Flask cookie、session与闪现

    02.Flask cookie.session与闪现 文章目录 02.Flask cookie.session与闪现 一.储备知识 1.什么是cookie? 注意点: 二.如何在flask中使用coo ...

  4. Flask 中内置的 Session

    Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪 1. Flask 中 session 是需要 secret_key 的 from ...

  5. JAVAWEB开发之Session的追踪创建和销毁、JSP详解(指令,标签,内置对象,动作即转发和包含)、JavaBean及内省技术以及EL表达式获取内容的使用

    Session的追踪技术 已知Session是利用cookie机制的服务器端技术,当客户端第一次访问资源时 如果调用request.getSession() 就会在服务器端创建一个由浏览器独享的ses ...

  6. JAVAWEB开发之Session的追踪创建和销毁、JSP具体解释(指令,标签,内置对象,动作即转发和包括)、JavaBean及内省技术以及EL表达式获取内容的使用...

    Session的追踪技术 已知Session是利用cookie机制的server端技术.当client第一次訪问资源时 假设调用request.getSession() 就会在server端创建一个由 ...

  7. JSP的概念||原理||JSP的脚本||JSP的内置对象||response.getWriter()和out.write()的区别||案例:改造Cookie案例

    1. 概念 * Java Server Pages: java服务器端页面         * 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码         * ...

  8. JavaWeb——内置对象session与httpSession对象是同一个东西么?

    JavaWeb--内置对象session与httpSession对象是同一个东西么? 首先,内置对象session与httpSession对象不是同一个东西 session和HttpSession是不 ...

  9. python中f点flush是什么函数_Python文件操作及内置函数flush原理解析

    1.打开文件得到文件句柄并赋值给一个变量 2.通过句柄对文件进行操作 3.关闭文件 示例文件 '你好呀' 我是于超 嗯 再见 文件操作基本流程 f=open('chenli',encoding='ut ...

最新文章

  1. mac hdmi 不能调整音量_如何使用Mac的媒体键在DisplayPortHDMI或Thunderbolt监视器上调整扬声器音量...
  2. curl-loader介绍
  3. python字典怎么设置_在python中设置字典中的属性
  4. oracle orapath,SQLNET.ORA中的NAMES.DIRECTORY_PATH设置
  5. 文件读写'r'和'rb'区别
  6. maven 打包时动态替换properties资源文件中的配置值
  7. 二十一天学通C#:.NET中文件与文件夹的操作
  8. 2018 为自己加油!
  9. 十字链表法和邻接多重表法
  10. 计算机软件系统由程序和相应的文档组成,ab计算机软件
  11. Matlab读取图像数据并写入TXT
  12. 4核处理器_最新版的MAC mini配M1处理器你会买吗?
  13. Android 从系统媒体库中选择视频
  14. 【torch】torch.roll
  15. pytorch中DataLoader的num_workers
  16. Python神经网络是这样识别手写字符哒?
  17. 绿联硬盘盒挂载linux,绿联sata硬盘盒,2.5/3.5寸外置usb3.0移动硬盘盒
  18. SMBIOS介绍(2):结构表
  19. 聊聊从逻辑门到操作系统的计算机
  20. “闪婚”的代价:亿晶光电控股权陷“罗生门”

热门文章

  1. r 保留之前曲线_生存曲线居然能够批量绘制了
  2. init tarray 太大_[NOIP 2001提高组T4]Car的旅行路线
  3. c语言 链表_C语言编程第22讲——单向有序链表的C语言实现
  4. linux査 到漠河 装apache,如何在Ubuntu上搭建一台安全的Apache Web服务器
  5. GDB与远程(交叉)GDB调试
  6. c ++明明的随机数_从列表C ++程序中随机建议电影
  7. 十一、非规则组织分析及其数学模型——芦席斜纹组织
  8. Python---正则表达式
  9. 简单的登录系统(java+JFrame+Mysql)
  10. 2020计算机二级题库第14PPT,计算机二级考试MSOffice考精彩试题库ppt操作题附问题详解.doc...