目录:

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

涉及知识点

1、装饰器

闭包思想

  1. def wapper(func):
  2. def inner(*args,**kwargs):
  3. return func(*args,**kwargs)
  4. return inner
  5.  
  6. """
  7. 1. 立即执行wapper函数,并将下面装饰的函数当做参数传递
  8. 2. 将wapper函数返回值获取,在index赋值
  9. index = inner函数
  10. """
  11. @wapper
  12. def index():
  13. print('函数内容')
  14.  
  15. # 实际执行的 inner函数,inner函数内部调用原函数
  16. index()

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

  1. import functools
  2. def wapper(func):
  3. @functools.wraps(func)
  4. def inner(*args,**kwargs):
  5. return func(*args,**kwargs)
  6. return inner
  7.  
  8. @wapper
  9. def index():
  10. print('函数内容')
  11.  
  12. @wapper
  13. def order():
  14. print('函数内容')
  15.  
  16. print(index.__name__)
  17. print(order.__name__)

2、面向对象封装

  1. class Foo(object):
  2. def __init__(self,age,name):
  3. self.age = age
  4. self.name = name
  5.  
  6. class Bar(object):
  7. def __init__(self,counter):
  8. self.counter = counter
  9. self.obj = Foo('','石鹏')
  10.  
  11. b1 = Bar(1)
  12. print(b1.obj.name)

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

  1. - 函数
    -
    - 方法
    - 对象
  1. def f1():
  2. print('f1')
  3.  
  4. class F2(object):
  5. pass
  6.  
  7. class F3(object):
  8. def __init__(self):
  9. pass
  10.  
  11. def ff3(self):
  12. print('ff3')
  13.  
  14. class F4(object):
  15. def __init__(self):
  16. pass
  17.  
  18. def __call__(self, *args, **kwargs):
  19. print('f4')
  20.  
  21. def func(arg):
  22. """
  23. 由于arg在函数中加括号,所以他只有4中表现形式:
  24. - 函数
  25. - 类
  26. - 方法
  27. - 对象
  28. :param arg:
  29. :return:
  30. """
  31. arg()
  32.  
  33. # 1. 函数,内部执行函数
  34. func(f1)
  35. # 2. 类,内部执行__init__方法
  36. func(F2)
  37.  
  38. # 3. 方法,obj.ff3
  39. obj1 = F3()
  40. func(obj1.ff3)
  41.  
  42. # 4. 对象
  43. obj2 = F4()
  44. func(obj2)

4、call方法

  1. class F4(object):
  2. def __init__(self):
  3. print('构造方法')
  4.  
  5. def __call__(self, *args, **kwargs):
  6. print('f4')
  7.  
  8. def run(self,str1):
  9. print("run:%s" % str1)
  10.  
  11. obj = F4()
  12. obj()
  13. obj.run('sssss')

5、函数和方法的区别

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

  1. from types import MethodType,FunctionType
  2.  
  3. class F3(object):
  4. def __init__(self):
  5. pass
  6.  
  7. def ff3(self):
  8. print('ff3')
  9.  
  10. #
  11. v1 = isinstance(F3.ff3,MethodType) # 方法
  12. v2 = isinstance(F3.ff3,FunctionType) # 函数
  13. print(v1,v2) # False,True
  14.  
  15. obj = F3()
  16. v1 = isinstance(obj.ff3,MethodType) # 方法
  17. v2 = isinstance(obj.ff3,FunctionType) # 函数
  18. print(v1,v2) # True False

Flask框架原理

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

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

  1. import socket
  2.  
  3. def main():
  4. # 创建老师
  5. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  6. sock.bind(('localhost', 8000))
  7. sock.listen(5)
  8.  
  9. while True:
  10. # 老师等待 用户请求的到来
  11. connection, address = sock.accept()
  12.  
  13. # 获取发送的内容:吴亦凡有没有女朋友?
  14. buf = connection.recv(1024)
  15.  
  16. # 根据请求URL的不同:
  17. # 回答:没有
  18. connection.send(b"HTTP/1.1 200 OK\r\n\r\n")
  19. connection.send(b"No No No")
  20.  
  21. # 关闭连接
  22. connection.close()
  23.  
  24. if __name__ == '__main__':
  25. main()

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

  1. """
  2. from werkzeug.wrappers import Request, Response
  3. from werkzeug.serving import run_simple
  4.  
  5. @Request.application
  6. def hello(request):
  7. return Response('Hello World!')
  8.  
  9. if __name__ == '__main__':
  10. # 当请求打来之后,自动执行:hello()
  11. run_simple('localhost', 4000, hello)
  12. """
  13.  
  14. from werkzeug.wrappers import Request, Response
  15. from werkzeug.serving import run_simple
  16.  
  17. class Foo(object):
  18. def __call__(self, *args, **kwargs):
  19. return Response('Hello World!')
  20.  
  21. if __name__ == '__main__':
  22. # 当请求打来之后,自动执行:hello()
  23. obj = Foo()
  24. run_simple('localhost', 4000, obj)

3、flask快速入门

  1. """
  2. pip install flask
  3. pip3 install flask
  4. """
  5.  
  6. from flask import Flask
  7. # 1. 实例化Flask对象
  8. app = Flask('xxxx')
  9.  
  10. """
  11. 1. 执行 app.route('/index')并获取返回值 xx
  12. 2.
  13. @xx
  14. def index():
  15. return 'Hello World'
  16. 3. 执行 index = xx(index)
  17. 本质:
  18. {
  19. '/index': index
  20. }
  21. """
  22. @app.route('/index')
  23. def index():
  24. return 'Hello World'
  25.  
  26. if __name__ == '__main__':
  27. app.run()

简单示例

1、实现简单登陆

  1. import functools
  2. from flask import Flask,render_template,request,redirect,session
  3.  
  4. app = Flask('xxxx',template_folder="templates")
  5. app.secret_key = 'as923lrjks9d8fwlkxlduf'
  6.  
  7. def auth(func):
  8. @functools.wraps(func)
  9. def inner(*args,**kwargs):
  10. user_info = session.get('user_info')
  11. if not user_info:
  12. return redirect('/login')
  13. return func(*args,**kwargs)
  14. return inner
  15.  
  16. """
  17. {
  18. /order: inner函数, name: order
  19. /index: inner函数, name: index
  20. }
  21. """
  22.  
  23. @app.route('/order',methods=['GET'])
  24. @auth
  25. def order():
  26. user_info = session.get('user_info')
  27. if not user_info:
  28. return redirect('/login')
  29.  
  30. return render_template('index.html')
  31.  
  32. @app.route('/index',methods=['GET'])
  33. @auth
  34. def index():
  35. return render_template('index.html')
  36.  
  37. @app.route('/login',methods=['GET','POST'])
  38. def login():
  39. if request.method == "GET":
  40. return render_template('login.html')
  41. else:
  42. user = request.form.get('user')
  43. pwd = request.form.get('pwd')
  44. if user == 'alex' and pwd == '':
  45. session['user_info'] = user
  46. return redirect('/index')
  47. # return render_template('login.html',msg = "用户名或密码错误",x = 123)
  48. return render_template('login.html',**{'msg':'用户名或密码错误'})
  49.  
  50. @app.route('/logout',methods=['GET'])
  51. def logout():
  52. del session['user_info']
  53. return redirect('/login')
  54.  
  55. if __name__ == '__main__':
  56. app.run()

app.py

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>登录页面</h1>
  9. <form method="post">
  10. <input type="text" name="user">
  11. <input type="password" name="pwd">
  12. <input type="submit" value="提交">{{msg}}
  13. </form>
  14. </body>
  15. </html>

templates/login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>欢迎进入系统</h1>
  9. <img src="/static/111.png" alt="">
  10. </body>
  11. </html>

templates/index.html

2、flask配置文件

  1. import functools
  2. from flask import Flask
  3.  
  4. # 配置:模板/静态文件
  5. app = Flask('xxxx',template_folder="templates")
  6. # 配置:secret_key
  7. app.secret_key = 'as923lrjks9d8fwlkxlduf'
  8.  
  9. # 导入配置文件
  10. app.config.from_object('settings.TestingConfig')
  11.  
  12. @app.route('/index')
  13. def index():
  14. return "index"
  15.  
  16. if __name__ == '__main__':
  17. app.run()
  1. class BaseConfig(object):
  2. DEBUG = False
  3. SESSION_REFRESH_EACH_REQUEST = True
  4.  
  5. class ProConfig(BaseConfig):
  6. pass
  7.  
  8. class DevConfig(BaseConfig):
  9. DEBUG = True
  10.  
  11. class TestingConfig(BaseConfig):
  12. 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中

  1. import functools
  2. from flask import Flask,views
  3.  
  4. # 配置:模板/静态文件
  5. app = Flask('xxxx',template_folder="templates")
  6. """
  7. {
  8. '/index': index函数
  9. }
  10.  
  11. 1. decorator = app.route('/index')
  12. 2.
  13. @decorator
  14. def index():
  15. return "index"
  16. 3. decorator(index)
  17. """
  18.  
  19. """
  20. Map() = [
  21. Rule(rule=/index/ endpoint=None view_func=函数),
  22. ]
  23. """
  24. @app.route('/index')
  25. def index():
  26. return "index"
  27.  
  28. """
  29. Map() = [
  30. Rule(rule=/index endpoint=None view_func=函数),
  31. Rule(rule=/order endpoint=None view_func=order),
  32. ]
  33. """
  34. def order():
  35. return 'Order'
  36. app.add_url_rule('/order', None, order)
  37.  
  38. class TestView(views.View):
  39. methods = ['GET']
  40. def dispatch_request(self):
  41. return 'test!'
  42.  
  43. app.add_url_rule('/test', view_func=TestView.as_view(name='test')) # name=endpoint
  44. # app.add_url_rule('/test', view_func=view函数) # name=endpoint
  45.  
  46. def auth(func):
  47. def inner(*args, **kwargs):
  48. print('before')
  49. result = func(*args, **kwargs)
  50. print('after')
  51. return result
  52. return inner
  53.  
  54. class X1View(views.MethodView):
  55. methods = ['GET','POST']
  56. decorators = [auth, ]
  57.  
  58. def get(self):
  59. return 'x1.GET'
  60.  
  61. def post(self):
  62. return 'x1.POST'
  63.  
  64. app.add_url_rule('/x1', view_func=X1View.as_view(name='x1')) # name=endpoint
  65.  
  66. if __name__ == '__main__':
  67. app.run()

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

  1. #--------------------------------------
  2. # Flask类
  3. class Flask(_PackageBoundObject):
  4. url_rule_class = Rule
  5. def __init__(self, import_name, static_path=None, static_url_path=None,
  6. static_folder='static', template_folder='templates',
  7. instance_path=None, instance_relative_config=False,
  8. root_path=None)
  9. self.url_map = Map()
  10.  
  11. #--------------------------------------
  12. # Role类
  13. @implements_to_string
  14. class Rule(RuleFactory):
  15. def __init__(self, string, defaults=None, subdomain=None, methods=None,
  16. build_only=False, endpoint=None, strict_slashes=None,
  17. redirect_to=None, alias=False, host=None):
  18. if not string.startswith('/'):
  19. raise ValueError('urls must start with a leading slash')
  20. self.rule = string
  21. self.is_leaf = not string.endswith('/')
  22.  
  23. self.map = None
  24. self.strict_slashes = strict_slashes
  25. self.subdomain = subdomain
  26. self.host = host
  27. self.defaults = defaults
  28. self.build_only = build_only
  29. self.alias = alias
  30. if methods is None:
  31. self.methods = None
  32. else:
  33. if isinstance(methods, str):
  34. raise TypeError('param `methods` should be `Iterable[str]`, not `str`')
  35. self.methods = set([x.upper() for x in methods])
  36. if 'HEAD' not in self.methods and 'GET' in self.methods:
  37. self.methods.add('HEAD')
  38. self.endpoint = endpoint
  39. self.redirect_to = redirect_to
  40.  
  41. if defaults:
  42. self.arguments = set(map(str, defaults))
  43. else:
  44. self.arguments = set()
  45. self._trace = self._converters = self._regex = self._weights = None
  46.  
  47. #-------------------
  48. #map类
  49. class Map(object):
  50. default_converters = ImmutableDict(DEFAULT_CONVERTERS)
  51.  
  52. def __init__(self, rules=None, default_subdomain='', charset='utf-8',
  53. strict_slashes=True, redirect_defaults=True,
  54. converters=None, sort_parameters=False, sort_key=None,
  55. encoding_errors='replace', host_matching=False):
  56. self._rules = []
  57. self._rules_by_endpoint = {}
  58. self._remap = True
  59. self._remap_lock = Lock()
  60.  
  61. self.default_subdomain = default_subdomain
  62. self.charset = charset
  63. self.encoding_errors = encoding_errors
  64. self.strict_slashes = strict_slashes
  65. self.redirect_defaults = redirect_defaults
  66. self.host_matching = host_matching
  67.  
  68. self.converters = self.default_converters.copy()
  69. if converters:
  70. self.converters.update(converters)
  71.  
  72. self.sort_parameters = sort_parameters
  73. self.sort_key = sort_key
  74.  
  75. for rulefactory in rules or ():
  76. self.add(rulefactory)

3、调用app.route方法

  1. def route(self, rule, **options):
  2. def decorator(f):
  3. endpoint = options.pop('endpoint', None)
  4. self.add_url_rule(rule, endpoint, f, **options)
  5. return f
  6. return decorator

4、route方法调用add_url_rule方法

  1. @setupmethod
  2. def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
  3. if endpoint is None:
  4. endpoint = _endpoint_from_view_func(view_func)
  5. options['endpoint'] = endpoint
  6. methods = options.pop('methods', None)
  7.  
  8. # if the methods are not given and the view_func object knows its
  9. # methods we can use that instead. If neither exists, we go with
  10. # a tuple of only ``GET`` as default.
  11. if methods is None:
  12. methods = getattr(view_func, 'methods', None) or ('GET',)
  13. if isinstance(methods, string_types):
  14. raise TypeError('Allowed methods have to be iterables of strings, '
  15. 'for example: @app.route(..., methods=["POST"])')
  16. methods = set(item.upper() for item in methods)
  17.  
  18. # Methods that should always be added
  19. required_methods = set(getattr(view_func, 'required_methods', ()))
  20.  
  21. # starting with Flask 0.8 the view_func object can disable and
  22. # force-enable the automatic options handling.
  23. provide_automatic_options = getattr(view_func,
  24. 'provide_automatic_options', None)
  25.  
  26. if provide_automatic_options is None:
  27. if 'OPTIONS' not in methods:
  28. provide_automatic_options = True
  29. required_methods.add('OPTIONS')
  30. else:
  31. provide_automatic_options = False
  32.  
  33. # Add the required methods now.
  34. methods |= required_methods
  35.  
  36. rule = self.url_rule_class(rule, methods=methods, **options)
  37. rule.provide_automatic_options = provide_automatic_options
  38.  
  39. 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方法

  1. def add(self, rulefactory):
  2. """Add a new rule or factory to the map and bind it. Requires that the
  3. rule is not bound to another map.
  4.  
  5. :param rulefactory: a :class:`Rule` or :class:`RuleFactory`
  6. """
  7. for rule in rulefactory.get_rules(self):
  8. rule.bind(self)
  9. self._rules.append(rule)
  10. self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
  11. 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

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

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

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

4、request_context对象__init__进行实例化

  1. def request_context(self, environ):
  2. return RequestContext(self, environ)

--request = app.request_class(environ)

  1. def __init__(self, app, environ, request=None):
  2. self.app = app
  3. if request is None:
  4. request = app.request_class(environ)
  5. self.request = request
  6. self.url_adapter = app.create_url_adapter(self.request)
  7. self.flashes = None
  8. self.session = None
  9.  
  10. # Request contexts can be pushed multiple times and interleaved with
  11. # other request contexts. Now only if the last level is popped we
  12. # get rid of them. Additionally if an application context is missing
  13. # one is created implicitly so for each level we add this information
  14. self._implicit_app_ctx_stack = []
  15.  
  16. # indicator if the context was preserved. Next time another context
  17. # is pushed the preserved context is popped.
  18. self.preserved = False
  19.  
  20. # remembers the exception for pop if there is one in case the context
  21. # preservation kicks in.
  22. self._preserved_exc = None
  23.  
  24. # Functions that should be executed after the request on the response
  25. # object. These will be called before the regular "after_request"
  26. # functions.
  27. self._after_request_functions = []
  28.  
  29. self.match_request()

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

  1. class Flask(_PackageBoundObject):
  1.   request_class = Request

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

  1. class Request(RequestBase):
  2. #: The internal URL rule that matched the request. This can be
  3. #: useful to inspect which methods are allowed for the URL from
  4. #: a before/after handler (``request.url_rule.methods``) etc.
  5. #:
  6. #: .. versionadded:: 0.6
  7. url_rule = None
  8.  
  9. #: A dict of view arguments that matched the request. If an exception
  10. #: happened when matching, this will be ``None``.
  11. view_args = None
  12.  
  13. #: If matching the URL failed, this is the exception that will be
  14. #: raised / was raised as part of the request handling. This is
  15. #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
  16. #: something similar.
  17. routing_exception = None
  18.  
  19. # Switched by the request context until 1.0 to opt in deprecated
  20. # module functionality.
  21. _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

  1. def wsgi_app(self, environ, start_response):
  2. ctx = self.request_context(environ)
  3. ctx.push()
  4. error = None
  5. try:
  6. try:
  7. # 4 执行视图函数
  8. response = self.full_dispatch_request()
  9. except Exception as e:
  10. # 异常处理试图报错,包含信号2345报错执行,got_request_exception信号
  11. error = e
  12. response = self.handle_exception(e)
  13. except:
  14. error = sys.exc_info()[1]
  15. raise
  16. # 将处理的内容,返回给用户浏览器
  17. return response(environ, start_response)
  18. finally:
  19. if self.should_ignore_error(error):
  20. error = None
  21.  
  22. # 9、结束
  23. ctx.auto_pop(error)

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

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

3、self.session调用app.open_session

  1. class RequestContext(object):
  2.   def push(self):
  3.   self.session = self.app.open_session(self.request)
  4.   if self.session is None:
  5.   self.session = self.app.make_null_session()

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

  1. class Flask(_PackageBoundObject):
  2. session_interface = SecureCookieSessionInterface()

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

  1. class SecureCookieSessionInterface(SessionInterface):
  2. """The default session interface that stores sessions in signed cookies
  3. through the :mod:`itsdangerous` module.
  4. """
  5. #: the salt that should be applied on top of the secret key for the
  6. #: signing of cookie based sessions.
  7. salt = 'cookie-session'
  8. #: the hash function to use for the signature. The default is sha1
  9. digest_method = staticmethod(hashlib.sha1)
  10. #: the name of the itsdangerous supported key derivation. The default
  11. #: is hmac.
  12. key_derivation = 'hmac'
  13. #: A python serializer for the payload. The default is a compact
  14. #: JSON derived serializer with support for some extra Python types
  15. #: such as datetime objects or tuples.
  16. serializer = session_json_serializer
  17. session_class = SecureCookieSession
      
  1.   
  1.   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

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

7、执行视图函数

response = self.full_dispatch_request()

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

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

----调用preprocess_request(before_request)

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

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

8、finalize_request

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

  1. def finalize_request(self, rv, from_error_handler=False):
  2. ''' 创建返视图返回'''
  3. response = self.make_response(rv)
  4. try:
  5. '''返回值'''
  6. response = self.process_response(response)
  7. # 执行信号request_finished
  8. request_finished.send(self, response=response)
  9. except Exception:
  10. if not from_error_handler:
  11. raise
  12. self.logger.exception('Request finalizing failed with an '
  13. 'error while handling an error')
  14. return response

9、process_response

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

  1. def process_response(self, response):
  2. ctx = _request_ctx_stack.top
  3. bp = ctx.request.blueprint
  4. funcs = ctx._after_request_functions
  5. if bp is not None and bp in self.after_request_funcs:
  6. funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
  7. if None in self.after_request_funcs:
  8. funcs = chain(funcs, reversed(self.after_request_funcs[None]))
  9. # 执行 after_request装饰器
  10. for handler in funcs:
  11. response = handler(response)
  12. # 将内存中的session持久化到:数据库、....
  13. if not self.session_interface.is_null_session(ctx.session):
  14. self.save_session(ctx.session, response)
  15. return response

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

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

11、save_session保存session,报错return null

  1. SecureCookieSessionInterface类:
  2. def save_session(self, app, session, response):
  3. domain = self.get_cookie_domain(app) # 域名
  4. path = self.get_cookie_path(app) # 路径
  5.  
  6. # Delete case. If there is no session we bail early.
  7. # If the session was modified to be empty we remove the
  8. # whole cookie.
  9. if not session:
  10. if session.modified:
  11. response.delete_cookie(app.session_cookie_name,
  12. domain=domain, path=path)
  13. return
  14.  
  15. # Modification case. There are upsides and downsides to
  16. # emitting a set-cookie header each request. The behavior
  17. # is controlled by the :meth:`should_set_cookie` method
  18. # which performs a quick check to figure out if the cookie
  19. # should be set or not. This is controlled by the
  20. # SESSION_REFRESH_EACH_REQUEST config flag as well as
  21. # the permanent flag on the session itself.
  22. if not self.should_set_cookie(app, session):
  23. return
  24.  
  25. httponly = self.get_cookie_httponly(app)
  26. secure = self.get_cookie_secure(app)
  27. expires = self.get_expiration_time(app, session)
  28. val = self.get_signing_serializer(app).dumps(dict(session)) # 加密
  29. response.set_cookie(app.session_cookie_name, val, # 最后保存在cookie中
  30. expires=expires, httponly=httponly,
  31. domain=domain, path=path, secure=secure)

附录

Flask系列之源码分析(一)的更多相关文章

  1. Flask系列之源码分析(二)

    应用技术点 python之__setattr__ python之threading.local python之偏函数 flask源码上下文管理 1.综述过程 将请求对象压入栈 1.请求进入 __cal ...

  2. Spring基础系列-AOP源码分析

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...

  3. flask/app.py-add_url_rule源码分析

    之前分析route方法的时候,可以看到中间会调用add_url_rule方法,add_url_rule方法和route方法一样属于Flask这个类的. add_url_rule方法主要用来连接url规 ...

  4. Tomcat详解系列(3) - 源码分析准备和分析入口

    Tomcat - 源码分析准备和分析入口 上文我们介绍了Tomcat的架构设计,接下来我们便可以下载源码以及寻找源码入口了.@pdai 源代码下载和编译 首先是去官网下载Tomcat的源代码和二进制安 ...

  5. Flask之wtforms源码分析

    一.wtforms源码流程 1.实例化流程分析 # 源码流程 1. 执行type的 __call__ 方法,读取字段到静态字段 cls._unbound_fields 中: meta类读取到cls._ ...

  6. Kafka源码系列之源码分析zookeeper在kafka的作用

    浪尖的kafka源码系列以kafka0.8.2.2源码为例给大家进行讲解的.纯属个人爱好,希望大家对不足之处批评指正. 一,zookeeper在分布式集群的作用 1,数据发布与订阅(配置中心) 发布与 ...

  7. Android进阶系列之源码分析Activity的启动流程

    美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...

  8. flask请求上下文源码分析

    一.什么是上下文 每一段程序都有很多外部变量,只有像add这种简单的函数才是没有外部变量的,一旦你的一段程序有了外部变量,这段程序就不完整了,不能独立运行,你为了使他们能运行,就要给所有的外部变量一个 ...

  9. Spring IOC 容器源码分析系列文章导读

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

随机推荐

  1. 浅析Linux内核同步机制

    非常早之前就接触过同步这个概念了,可是一直都非常模糊.没有深入地学习了解过,最近有时间了,就花时间研习了一下<linux内核标准教程>和<深入linux设备驱动程序内核机制>这 ...

  2. Mac普通用户修改了/etc/sudoers文件的解决办法

    1.开启 Root 账户 打开“系统偏好设置”,进入“用户与群组”面板,记得把面板左下角的小锁打开,然后选择面板里的“登录选项”.在面板右边你会看到“网络账户服务 器”,点击它旁边的“加入…”按钮,再 ...

  3. 【RF库Collections测试】Count Values In List

    Name:Count Values In ListSource:Collections <test library>Arguments:[ list_ | value | start=0 ...

  4. linux系统socket通信编程2

    一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...

  5. linux系统usb挂载

    本次例程的环境是在FC6下,通过终端操作的. 注意要挂载U盘需要有管理员的权限. 切换成管理员,输入: su root 然后输入管理员密码,进行密码认证: 成功后,先在 /mnt 下建立一个名叫USB ...

  6. cocos2dx游戏--欢欢英雄传说--添加血条

    用一个空血槽图片的Sprite做背景,上面放一个ProgressTimer, 通过设置ProgressTimer的进度来控制血条的长短.建立一个Progress类来实现.Progress.h: #if ...

  7. Android AndroidManifest.xml配置文件

    AndroidManifest.xml配置文件介绍本质:AndroidManifest.xml是整个应用的主配置清单文件.包含:该应用的包名.版本号.组件.权限等信息.作用:记录该应用的相关配置信息. ...

  8. php第一例

    参考 例子 https://www.cnblogs.com/chinajins/p/5622342.html 配置多个网站 https://blog.csdn.net/win7system/artic ...

  9. js offset

    1.offsetParent offsetParent属性返回一个对象的引用,这个对象是距离调用offsetParent的元素最近的(在包含层次中最靠近的),并且是已进行过CSS定位的容器元素. 如果 ...

  10. gradle下的第一个SpringMVC应用

    新建gradle project 缺少了很多文件夹和文件,我们自己补充,补充完的目录如下: HelloController: package controller; import javax.serv ...