• Flask系列之源码分析(一)


    目录:

    • 涉及知识点
    • Flask框架原理
    • 简单示例
    • 路由系统原理源码分析
    • 请求流程简单源码分析
    • 响应流程简单源码分析
    • session简单源码分析

    涉及知识点

    1、装饰器

    闭包思想

    def wapper(func):
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    """
    1. 立即执行wapper函数,并将下面装饰的函数当做参数传递
    2. 将wapper函数返回值获取,在index赋值
        index = inner函数
    """
    @wapper
    def index():
        print('函数内容')
    
    # 实际执行的 inner函数,inner函数内部调用原函数
    index()
    View Code

    ps.@functools.wraps,以上我们知道了python实现闭包,实际是index = inner(index)的封装思想。但不可避免的是inner封装后,会对封装的函数隐藏一些信息。如:包装异常,隐藏异常,打印日志,统计函数使用时间等。@functools.wraps通过update_wrapper函数,用参数wrapped表示的函数对象(例如:square)的一些属性(如:__name__、 __doc__)覆盖参数wrapper表示的函数对象(例如:callf,这里callf只是简单地调用square函数,因此可以说callf是 square的一个wrapper function)的这些相应属性。

    import functools
    def wapper(func):
        @functools.wraps(func)
        def inner(*args,**kwargs):
            return func(*args,**kwargs)
        return inner
    
    @wapper
    def index():
        print('函数内容')
    
    @wapper
    def order():
        print('函数内容')
    
    print(index.__name__)
    print(order.__name__)
    View Code

    2、面向对象封装

    class Foo(object):
        def __init__(self,age,name):
            self.age = age
            self.name = name
    
    class Bar(object):
        def __init__(self,counter):
            self.counter = counter
            self.obj = Foo('18','石鹏')
    
    b1 = Bar(1)
    print(b1.obj.name)
    View Code

    3、python对象什么后面可以加括号

    - 函数
    - 类
    - 方法
    - 对象
    def f1():
        print('f1')
    
    class F2(object):
        pass
    
    class F3(object):
        def __init__(self):
            pass
    
        def ff3(self):
            print('ff3')
    
    class F4(object):
        def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('f4')
    
    
    def func(arg):
        """
        由于arg在函数中加括号,所以他只有4中表现形式:
            - 函数
            - 类
            - 方法
            - 对象
        :param arg:
        :return:
        """
        arg()
    
    # 1. 函数,内部执行函数
    func(f1)
    # 2. 类,内部执行__init__方法
    func(F2)
    
    # 3. 方法,obj.ff3
    obj1 = F3()
    func(obj1.ff3)
    
    # 4. 对象
    obj2 = F4()
    func(obj2)
    View Code

    4、call方法

    class F4(object):
        def __init__(self):
            print('构造方法')
    
        def __call__(self, *args, **kwargs):
            print('f4')
    
        def run(self,str1):
            print("run:%s" % str1)
    
    obj = F4()
    obj()
    obj.run('sssss')
    View Code

    5、函数和方法的区别

    在于调用时有没有实例化对象,即跟某个对象关联。

    from types import MethodType,FunctionType
    
    
    class F3(object):
        def __init__(self):
            pass
    
        def ff3(self):
            print('ff3')
    
    #
    v1 = isinstance(F3.ff3,MethodType)  # 方法
    v2 = isinstance(F3.ff3,FunctionType) # 函数
    print(v1,v2) # False,True
    
    obj = F3()
    v1 = isinstance(obj.ff3,MethodType)  # 方法
    v2 = isinstance(obj.ff3,FunctionType) # 函数
    print(v1,v2) # True False
    View Code

    Flask框架原理

    1、框架本质为通过socket模块实现工作流的请求和响应。

    通过socket建立实例,accept等待请求地址,并通过编写路由系统来给予相应的响应。

    import socket
    
    def main():
        # 创建老师
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('localhost', 8000))
        sock.listen(5)
    
        while True:
            # 老师等待 用户请求的到来
            connection, address = sock.accept()
            
            # 获取发送的内容:吴亦凡有没有女朋友?
            buf = connection.recv(1024)
    
            # 根据请求URL的不同:
            # 回答:没有
            connection.send(b"HTTP/1.1 200 OK
    
    ")
            connection.send(b"No No No")
    
            # 关闭连接
            connection.close()
    
    
    if __name__ == '__main__':
        main()

    2、flask通过werkzeug模块来帮助我们完成socket性能。

    """
    from werkzeug.wrappers import Request, Response
    from werkzeug.serving import run_simple
    
    @Request.application
    def hello(request):
        return Response('Hello World!')
    
    if __name__ == '__main__':
        # 当请求打来之后,自动执行:hello()
        run_simple('localhost', 4000, hello)
    """
    
    
    from werkzeug.wrappers import Request, Response
    from werkzeug.serving import run_simple
    
    class Foo(object):
        def __call__(self, *args, **kwargs):
            return Response('Hello World!')
    
    if __name__ == '__main__':
        # 当请求打来之后,自动执行:hello()
        obj = Foo()
        run_simple('localhost', 4000, obj)
    View Code

    3、flask快速入门

    """
    pip install flask
    pip3 install flask
    """
    
    from flask import Flask
    # 1. 实例化Flask对象
    app = Flask('xxxx')
    
    """
    1. 执行 app.route('/index')并获取返回值 xx
    2. 
        @xx
        def index():
            return 'Hello World'
    3. 执行 index = xx(index)
    本质: 
        {
            '/index': index
        }
    """
    @app.route('/index')
    def index():
        return 'Hello World'
    
    
    if __name__ == '__main__':
        app.run()
    View Code

    简单示例

    1、实现简单登陆

    import functools
    from flask import Flask,render_template,request,redirect,session
    
    app = Flask('xxxx',template_folder="templates")
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    
    
    def auth(func):
        @functools.wraps(func)
        def inner(*args,**kwargs):
            user_info = session.get('user_info')
            if not user_info:
                return redirect('/login')
            return func(*args,**kwargs)
        return inner
    
    
    """
    {
        /order: inner函数, name: order
        /index: inner函数, name: index
    }
    """
    
    @app.route('/order',methods=['GET'])
    @auth
    def order():
        user_info = session.get('user_info')
        if not user_info:
            return redirect('/login')
    
        return render_template('index.html')
    
    
    @app.route('/index',methods=['GET'])
    @auth
    def index():
        return render_template('index.html')
    
    
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method == "GET":
            return render_template('login.html')
        else:
            user = request.form.get('user')
            pwd = request.form.get('pwd')
            if user == 'alex' and pwd == '123':
                session['user_info'] = user
                return redirect('/index')
            # return render_template('login.html',msg = "用户名或密码错误",x =  123)
            return render_template('login.html',**{'msg':'用户名或密码错误'})
    
    @app.route('/logout',methods=['GET'])
    def logout():
        del session['user_info']
        return redirect('/login')
    
    if __name__ == '__main__':
        app.run()
    app.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>登录页面</h1>
        <form method="post">
            <input type="text" name="user">
            <input type="password" name="pwd">
            <input type="submit" value="提交">{{msg}}
        </form>
    </body>
    </html>
    templates/login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>欢迎进入系统</h1>
        <img src="/static/111.png" alt="">
    </body>
    </html>
    templates/index.html

    2、flask配置文件

    import functools
    from flask import Flask
    
    # 配置:模板/静态文件
    app = Flask('xxxx',template_folder="templates")
    # 配置:secret_key
    app.secret_key = 'as923lrjks9d8fwlkxlduf'
    
    # 导入配置文件
    app.config.from_object('settings.TestingConfig')
    
    
    @app.route('/index')
    def index():
        return "index"
    
    
    
    if __name__ == '__main__':
        app.run()
    View Code
    class BaseConfig(object):
        DEBUG = False
        SESSION_REFRESH_EACH_REQUEST = True
    
    class ProConfig(BaseConfig):
        pass
    
    class DevConfig(BaseConfig):
        DEBUG = True
    
    class TestingConfig(BaseConfig):
        DEBUG = True
    settings.py

    ps.import importlib模块,模块支持传递字符串来导入模块。我们先来创建一些简单模块一遍演示。我们在模块里提供了相同接口,通过打印它们自身名字来区分。可通过importlib.import_module(module_path)来动态导入。其等价于import module_path。

    路由系统原理源码分析

    1、总体流程:

    1.初始化Flask类,Rule类,Map类

    2.调用app.route方法

    3.route方法调用add_url_rule方法

    4. add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数

    5.add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]

    6.map类存到self.url_map中,Rule存在url_rule_class中

    import functools
    from flask import Flask,views
    
    # 配置:模板/静态文件
    app = Flask('xxxx',template_folder="templates")
    """
    {
        '/index': index函数
    }
    
    1. decorator = app.route('/index')
    2. 
        @decorator
        def index():
            return "index"
    3. decorator(index)
    """
    
    """
    Map() = [
        Rule(rule=/index/ endpoint=None  view_func=函数),
    ]
    """
    @app.route('/index')
    def index():
        return "index"
    
    """
    Map() = [
        Rule(rule=/index endpoint=None  view_func=函数),
        Rule(rule=/order endpoint=None  view_func=order),
    ]
    """
    def order():
        return 'Order'
    app.add_url_rule('/order', None, order)
    
    
    class TestView(views.View):
        methods = ['GET']
        def dispatch_request(self):
            return 'test!'
    
    app.add_url_rule('/test', view_func=TestView.as_view(name='test'))  # name=endpoint
    # app.add_url_rule('/test', view_func=view函数)  # name=endpoint
    
    
    def auth(func):
        def inner(*args, **kwargs):
            print('before')
            result = func(*args, **kwargs)
            print('after')
            return result
        return inner
    
    class X1View(views.MethodView):
        methods = ['GET','POST']
        decorators = [auth, ]
    
        def get(self):
            return 'x1.GET'
    
        def post(self):
            return 'x1.POST'
    
    
    app.add_url_rule('/x1', view_func=X1View.as_view(name='x1'))  # name=endpoint
    
    
    if __name__ == '__main__':
        app.run()
    View Code

    2、初始化Flask类,Rule类,Map类

    #--------------------------------------
    # Flask类
    class Flask(_PackageBoundObject):
        url_rule_class = Rule
        def __init__(self, import_name, static_path=None, static_url_path=None,
                     static_folder='static', template_folder='templates',
                     instance_path=None, instance_relative_config=False,
                     root_path=None)
            self.url_map = Map()
    
    #--------------------------------------
    # Role类
    @implements_to_string
    class Rule(RuleFactory):
            def __init__(self, string, defaults=None, subdomain=None, methods=None,
                     build_only=False, endpoint=None, strict_slashes=None,
                     redirect_to=None, alias=False, host=None):
            if not string.startswith('/'):
                raise ValueError('urls must start with a leading slash')
            self.rule = string
            self.is_leaf = not string.endswith('/')
    
            self.map = None
            self.strict_slashes = strict_slashes
            self.subdomain = subdomain
            self.host = host
            self.defaults = defaults
            self.build_only = build_only
            self.alias = alias
            if methods is None:
                self.methods = None
            else:
                if isinstance(methods, str):
                    raise TypeError('param `methods` should be `Iterable[str]`, not `str`')
                self.methods = set([x.upper() for x in methods])
                if 'HEAD' not in self.methods and 'GET' in self.methods:
                    self.methods.add('HEAD')
            self.endpoint = endpoint
            self.redirect_to = redirect_to
    
            if defaults:
                self.arguments = set(map(str, defaults))
            else:
                self.arguments = set()
            self._trace = self._converters = self._regex = self._weights = None
    
    #-------------------
    #map类
    class Map(object):
         default_converters = ImmutableDict(DEFAULT_CONVERTERS)
    
        def __init__(self, rules=None, default_subdomain='', charset='utf-8',
                     strict_slashes=True, redirect_defaults=True,
                     converters=None, sort_parameters=False, sort_key=None,
                     encoding_errors='replace', host_matching=False):
            self._rules = []
            self._rules_by_endpoint = {}
            self._remap = True
            self._remap_lock = Lock()
    
            self.default_subdomain = default_subdomain
            self.charset = charset
            self.encoding_errors = encoding_errors
            self.strict_slashes = strict_slashes
            self.redirect_defaults = redirect_defaults
            self.host_matching = host_matching
    
            self.converters = self.default_converters.copy()
            if converters:
                self.converters.update(converters)
    
            self.sort_parameters = sort_parameters
            self.sort_key = sort_key
    
            for rulefactory in rules or ():
                self.add(rulefactory)

    3、调用app.route方法

    def route(self, rule, **options):
            def decorator(f):
                endpoint = options.pop('endpoint', None)
                self.add_url_rule(rule, endpoint, f, **options)
                return f
            return decorator

    4、route方法调用add_url_rule方法

    @setupmethod
        def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
     if endpoint is None:
                endpoint = _endpoint_from_view_func(view_func)
            options['endpoint'] = endpoint
            methods = options.pop('methods', None)
    
            # if the methods are not given and the view_func object knows its
            # methods we can use that instead.  If neither exists, we go with
            # a tuple of only ``GET`` as default.
            if methods is None:
                methods = getattr(view_func, 'methods', None) or ('GET',)
            if isinstance(methods, string_types):
                raise TypeError('Allowed methods have to be iterables of strings, '
                                'for example: @app.route(..., methods=["POST"])')
            methods = set(item.upper() for item in methods)
    
            # Methods that should always be added
            required_methods = set(getattr(view_func, 'required_methods', ()))
    
            # starting with Flask 0.8 the view_func object can disable and
            # force-enable the automatic options handling.
            provide_automatic_options = getattr(view_func,
                'provide_automatic_options', None)
    
            if provide_automatic_options is None:
                if 'OPTIONS' not in methods:
                    provide_automatic_options = True
                    required_methods.add('OPTIONS')
                else:
                    provide_automatic_options = False
    
            # Add the required methods now.
            methods |= required_methods
    
            rule = self.url_rule_class(rule, methods=methods, **options)
            rule.provide_automatic_options = provide_automatic_options
    
            self.url_map.add(rule)

    5、 add_url_rule方法rule = self.url_rule_class调用Rule方法,封装url和试图函数

    add_url_rule,代码同4 ;通过url_rule_class = Rule实例化,代码同2

    6、add_url_rule方法调用url_map.add(Rule)对路由的rules进行添加[Rule('/index', 函数),]

    add_url_rule代码同4,调用url_map.add方法

        def add(self, rulefactory):
            """Add a new rule or factory to the map and bind it.  Requires that the
            rule is not bound to another map.
    
            :param rulefactory: a :class:`Rule` or :class:`RuleFactory`
            """
            for rule in rulefactory.get_rules(self):
                rule.bind(self)
                self._rules.append(rule)
                self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
            self._remap = True

    7.map类存到self.url_map中,Rule存在url_rule_class中。

    同代码2.

    请求流程简单源码分析

     1、综述:

    1.已生成路由后,由app.run执行run方法

    2.run方法通过werkzeug模块执行run_simple方法

    3.werkzeug模块会触发__call__方法

    4.__call__方法会触发wsgi_app

    5.ctx=request_context对象,触发request_context对象

    6.request_context对象__init__进行实例化

    --request = app.request_class(environ)

    7.flask初始化通过request实例化调用Request对象,通过request实例化调用Request对象

    8.Request对象通过werkzeug模块__init__进行实例化

    9.存储到ctx中

    10.ctx.push()调用RequestContest.push方法

    2、__call__方法会触发wsgi_app

        def __call__(self, environ, start_response):
            """Shortcut for :attr:`wsgi_app`."""
            return self.wsgi_app(environ, start_response)

    3、ctx=request_context对象,触发request_context对象

    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
        ctx.push()

    4、request_context对象__init__进行实例化

    def request_context(self, environ):
        return RequestContext(self, environ)

    --request = app.request_class(environ)

        def __init__(self, app, environ, request=None):
            self.app = app
            if request is None:
                request = app.request_class(environ)
            self.request = request
            self.url_adapter = app.create_url_adapter(self.request)
            self.flashes = None
            self.session = None
    
            # Request contexts can be pushed multiple times and interleaved with
            # other request contexts.  Now only if the last level is popped we
            # get rid of them.  Additionally if an application context is missing
            # one is created implicitly so for each level we add this information
            self._implicit_app_ctx_stack = []
    
            # indicator if the context was preserved.  Next time another context
            # is pushed the preserved context is popped.
            self.preserved = False
    
            # remembers the exception for pop if there is one in case the context
            # preservation kicks in.
            self._preserved_exc = None
    
            # Functions that should be executed after the request on the response
            # object.  These will be called before the regular "after_request"
            # functions.
            self._after_request_functions = []
    
            self.match_request()

    5、flask初始化通过request实例化调用Request对象,通过request实例化调用Request对象

    class Flask(_PackageBoundObject):
      request_class = Request

    6、Request对象通过werkzeug模块__init__进行实例化

    class Request(RequestBase):
         #: The internal URL rule that matched the request.  This can be
        #: useful to inspect which methods are allowed for the URL from
        #: a before/after handler (``request.url_rule.methods``) etc.
        #:
        #: .. versionadded:: 0.6
        url_rule = None
    
        #: A dict of view arguments that matched the request.  If an exception
        #: happened when matching, this will be ``None``.
        view_args = None
    
        #: If matching the URL failed, this is the exception that will be
        #: raised / was raised as part of the request handling.  This is
        #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
        #: something similar.
        routing_exception = None
    
        # Switched by the request context until 1.0 to opt in deprecated
        # module functionality.
        _is_old_module = False

    7、.存储到ctx中

    同3代码

    8、ctx.push()调用RequestContest.push方法

    同3代码

    flask的sesstion流程

    1、综述

    1.RequestContext.push,调用app.open_sesstion

    2.self.session调用app.open_session

    3.通过session_interface变量调用到secureCookieSeeionInerface类的open_session

    4.如果没有,则session_class = SecureCookieSession,open_session经过loads加密返回self.session_class(),

    5.将加密session返回到self.session

    6.执行视图函数

    response = self.full_dispatch_request()
    ----调用try_trigger_before_first_request_functions
    (before_first_request)
    ----调用preprocess_request(before_request)
    ----调用dispatch_request(执行试图函数)
    ----调用finalize_request(@fater_request)

    7.finalize_request

    ----response = self.process_response(response)

    8.process_response

    ----执行@fater_request函数
    ----self.save_session(ctx.session, response)

    9.通过self.save_session调用save_session并返回SecureCookieSessionInterface.save_session(self, session, response)

    10.save_session保存session,报错return null

     2、RequestContext.push,调用app.open_sesstion

    def wsgi_app(self, environ, start_response):
        ctx = self.request_context(environ)
            ctx.push()
            error = None
            try:
                try:
                    # 4 执行视图函数
                    response = self.full_dispatch_request()
                except Exception as e:
                    # 异常处理试图报错,包含信号2345报错执行,got_request_exception信号
                    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
    
                # 9、结束
                ctx.auto_pop(error)

    通过self.session = self.app.open_session(self.request)调用flask.open_session方法

    def open_session(self, request):
        return self.session_interface.open_session(self, request)

    3、self.session调用app.open_session

    class RequestContext(object):
      def push(self):
          self.session = self.app.open_session(self.request)
          if self.session is None:
              self.session = self.app.make_null_session()

    4、通过session_interface变量调用到secureCookieSeeionInerface类的open_session

    class Flask(_PackageBoundObject):
         session_interface = SecureCookieSessionInterface()

    5、如果没有,则session_class = SecureCookieSession,open_session经过loads加密返回self.session_class(),

    class SecureCookieSessionInterface(SessionInterface):
        """The default session interface that stores sessions in signed cookies
        through 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 sha1
        digest_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_serializer
        session_class = SecureCookieSession
      
      
      def open_session(self, app, request):
      # sission,key值
      s = self.get_signing_serializer(app)
      if s is None:
      return None
      # 如果能从cookie拿到session的话
      val = request.cookies.get(app.session_cookie_name)
      if not val:
      return self.session_class() #如果没有session,则返回一个空字典
      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() # 返回session类

    6、将加密session返回到self.session

    
    
    class RequestContext(object):
      def push(self):
          self.session = self.app.open_session(self.request)
          if self.session is None:
              self.session = self.app.make_null_session()

    7、执行视图函数

    response = self.full_dispatch_request()

    同代码2
    ----调用try_trigger_before_first_request_functions
    (before_first_request)

        def full_dispatch_request(self):
            """Dispatches the request and on top of that performs request
            pre and postprocessing as well as HTTP exception catching and
            error handling.
    
            .. versionadded:: 0.7
            """
            # 触发只执行一次的装饰器函数,@before_first_request
            self.try_trigger_before_first_request_functions()

    ----调用preprocess_request(before_request)

    ----调用dispatch_request(执行试图函数)
    ----调用finalize_request(@fater_request)

    def full_dispatch_request(self):
        try:
             # 执行特殊装饰器:before_request装饰的所有函数
             # 如果没有返回值,rv=None;有返回值 “嘻嘻嘻”
             rv = self.preprocess_request()
             if rv is None:
                    # 触发执行视图函数,使用session
                 rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
            # 6 对返回值进行封装,执行@fater_request装饰器;session保存
        return self.finalize_request(rv)

    8、finalize_request

    ----response = self.process_response(response)

     def finalize_request(self, rv, from_error_handler=False):
            ''' 创建返视图返回'''
            response = self.make_response(rv)
            try:
                '''返回值'''
                response = self.process_response(response)
                # 执行信号request_finished
                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

    9、process_response

    ----执行@fater_request函数
    ----self.save_session(ctx.session, 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]))
            # 执行 after_request装饰器
            for handler in funcs:
                response = handler(response)
            # 将内存中的session持久化到:数据库、....
            if not self.session_interface.is_null_session(ctx.session):
                self.save_session(ctx.session, response)
            return response

    10、通过self.save_session调用save_session并返回SecureCookieSessionInterface.save_session(self, session, response)

    # Flask类
    def
    save_session(self, session, response): return self.session_interface.save_session(self, session, response)

    11、save_session保存session,报错return null

    SecureCookieSessionInterface类:
        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):
                return
    
            httponly = 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,    # 最后保存在cookie中
                                expires=expires, httponly=httponly,
                                domain=domain, path=path, secure=secure)

     附录

  • 相关阅读:
    抓取猫眼电影top100的正则、bs4、pyquery、xpath实现方法
    Win实用好用软件清单推荐
    Manjaro安装配置美化字体模糊发虚解决记录
    爬取杭电oj所有题目
    Python爬取微博热搜以及链接
    20191225_Python构造函数知识以及相关注意事项
    java_细节_windows7下记事本保存为utf-8格式的问题
    基础_划分子网
    爬虫_爬取有道每日一句
    算法_基础_伪代码定义以及遵循的规则
  • 原文地址:https://www.cnblogs.com/wangshuyang/p/8854826.html
Copyright © 2020-2023  润新知