zoukankan      html  css  js  c++  java
  • 07 flask源码剖析之用户请求过来流程

    07 Flask源码之:用户请求过来流程

    1.创建ctx = RequestContext对象

    • RequestContext对象封装Request对象

    • RequestContext对象封装session数据

    • 源码实现:

      def wsgi_app(self, environ, start_response):
          """
              ctx = RequestContext(self, environ)
              """
          # 2.1 创建RequestContext对象
          ctx = self.request_context(environ)
      
      def request_context(self, environ):
          return RequestContext(self, environ)
      
      request_class = Request
      
      class RequestContext(object):
          def __init__(self, app, environ, request=None, session=None):
              self.app = app
              if request is None:
                  """
                  request_class = Request
                  """
                  request = app.request_class(environ)
              self.request = request
              self.session = session
      

    2. 创建app_ctx = AppContext对象

    • AppContext对象封装App对象

    • AppContext对象封装g

    • 源码实现:

      def wsgi_app(self, environ, start_response):
          """
              ctx = RequestContext(self, environ)
              """
          # 2.1 创建RequestContext对象
          ctx = self.request_context(environ)
          error = None
          try:
              try:
                  """
                  2.2 执行ctx.push
                      - app_ctx = 创建AppContext对象(app,g)
                      - 将app_ctx放入local中
                      - 将ctx放入到local中
                      - session赋值
                      - 路由匹配
                   """
                  ctx.push()
      
          def push(self):
              top = _request_ctx_stack.top
              if top is not None and top.preserved:
                  top.pop(top._preserved_exc)
              app_ctx = _app_ctx_stack.top
              if app_ctx is None or app_ctx.app != self.app:
                  """
                  app_ctx = AppContext(app)
                  """
                  # 创建appcontext对象
                  app_ctx = self.app.app_context()
      
      def app_context(self):
          return AppContext(self)
      
      class AppContext(object):
          def __init__(self, app):
              self.app = app
              self.g = app.app_ctx_globals_class()
      

    3. 将ctx对象、app_ctx对象放到local中

    • 然后ctx.push触发将 ctx对象,通过自己的LocalStack对象将其放入到Local中

    • 然后app_ctx.push触发将 app_ctx对象,通过自己的LocalStack对象将其放入到Local中

    • Local的本质是以线程ID为key,以{“stack”:[]}为value的字典

      存储结构:{
      1111:{“stack”:[ctx,]}
      };

      ​ {
      ​ 1111:{“stack”:[app_ctx,]}
      ​ }

    • 源码示例:

          def push(self):
              top = _request_ctx_stack.top
              if top is not None and top.preserved:
                  top.pop(top._preserved_exc)
              app_ctx = _app_ctx_stack.top
              if app_ctx is None or app_ctx.app != self.app:
                  """
                  app_ctx = AppContext(app)
                  """
                  # 创建appcontext对象
                  app_ctx = self.app.app_context()
                  # push将app_ctx放入到local中
                  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()
              """
              self = ctx = RequestContext(self, environ)
              """
              # push将ctx放入到local中
              _request_ctx_stack.push(self)
      
              if self.session is None:
                  session_interface = self.app.session_interface
                  self.session = session_interface.open_session(self.app, self.request)
      
                  if self.session is None:
                      self.session = session_interface.make_null_session(self.app)
      
              if self.url_adapter is not None:
                  # 路由匹配,将匹配到的endpoint放到request.url_rule中
                  self.match_request()
      

    4. 执行所有before_request函数以及所有的视图函数

    1. 执行full_dispatch_request函数
    2. 执行所有的before_request函数
    3. 执行视图函数
    • 源码示例:

      def wsgi_app(self, environ, start_response):
          """
              ctx = RequestContext(self, environ)
          """
          #2.1 创建RequestContext对象
          ctx = self.request_context(environ)
          error = None
          try:
              try:
                  # 做了很多事
                  """
                      2.2 执行ctx.push
                          - app_ctx = 创建AppContext对象(app,g)
                          - 将app_ctx放入local中
                          - 将ctx放入到local中
                          - session赋值
                          - 路由匹配
                   """
                  ctx.push()
                  # 2.3 执行before_request/视图/after_request (处理session)
                  response = self.full_dispatch_request()
      
      def full_dispatch_request(self):
          # 触发所有的before_first_request_funcs函数
          # 只在启动程序后,第一个请求到来时执行
          self.try_trigger_before_first_request_functions()
          try:
              # 信号,暂留
              request_started.send(self)
              # 执行before_request_funcs函数,如果有返回值就不执行视图函数了
              rv = self.preprocess_request()
              if rv is None:
                  # 执行视图函数
                  rv = self.dispatch_request()
                  except Exception as e:
                      rv = self.handle_user_exception(e)
                      # 视图函数执行之后
                      #  1.执行所有的after_request
                      #  2.保存session
                      return self.finalize_request(rv)
      

    5. 执行所有after_request函数

    • session会加密返回给用户浏览器放到cookie中

    • 源码示例:

      def finalize_request(self, rv, from_error_handler=False):
          # 将rv视图函数返回值,封装到Reponse对象中
          response = self.make_response(rv)
          response = self.process_response(response)
          return response
      
      response_class = Response
      
      def make_response(self, rv):
          if not isinstance(rv, self.response_class):
              if isinstance(rv, (text_type, bytes, bytearray)):
                  rv = self.response_class(rv, status=status, headers=headers)
                  return rv
      
      def process_response(self, response):
          ctx = _request_ctx_stack.top
          funcs = ctx._after_request_functions
          # 执行所有的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):
                  # 保存session
                  self.session_interface.save_session(self, ctx.session, response)
                  return response
      

    6. 销毁ctx和app_ctx

    • 如果请求结束不销毁ctx和app_ctx的话,会造成内存泄漏

    • 分别调用ctx和app_ctx的pop方法

    • 源码示例:

      def wsgi_app(self, environ, start_response):
          """
              ctx = RequestContext(self, environ)
          """
          #2.1 创建RequestContext对象
          ctx = self.request_context(environ)
          error = None
          try:
              try:
                  """
                      2.2 执行ctx.push
                          - app_ctx = 创建AppContext对象(app,g)
                          - 将app_ctx放入local中
                          - 将ctx放入到local中
                          - session赋值
                          - 路由匹配
                   """
                  ctx.push()
                  # 2.3 执行before_request/视图/after_request (处理session)
                  response = self.full_dispatch_request()
                  except Exception as e:
                      error = e
                      response = self.handle_exception(e)
                      except:  # noqa: B001
                          error = sys.exc_info()[1]
                          raise
                          return response(environ, start_response)
                      finally:
                          if self.should_ignore_error(error):
                              error = None
                              # 2.4 销毁ctx/app_ctx
                              ctx.auto_pop(error)
      
      
      def auto_pop(self, exc):
          self.pop(exc)
      
      def pop(self, exc=_sentinel):
          app_ctx = self._implicit_app_ctx_stack.pop()
          finally:
              rv = _request_ctx_stack.pop()
              if app_ctx is not None:
                  app_ctx.pop(exc)
      
  • 相关阅读:
    Android OpenGL ES 2.0 (四) 灯光perfragment lighting
    Android OpenGL ES 2.0 (五) 添加材质
    冒泡排序函数
    javascript object 转换为 json格式 toJSONString
    Liunx CentOS 下载地址
    jquery 图片切换特效 鼠标点击左右按钮焦点图切换滚动
    javascript 解析csv 的function
    mysql Innodb Shutdown completed; log sequence number解决办法
    Centos 添加 yum
    javascript 键值转换
  • 原文地址:https://www.cnblogs.com/liubing8/p/11930727.html
Copyright © 2011-2022 走看看