zoukankan      html  css  js  c++  java
  • flask请求流程,源码走读

    flask依赖werkezug和jinja2,flask处在中间,为两者建立一座桥梁,前者实现WSGI,后者处理模板。Flask 也绑定了一些通用的标准库包,比如 logging 。其它所有一切取决于扩展。


    什么是WSGI?

      Web服务网关接口,属于一套协议。是Python web开发中 web服务器与web应用程序之间数据交互的约定。网关协议的本质是为了解耦,实现web服务器和web应用程序的分离,WSGI就是一个支持WSGI的web服务器与Python web应用程序之间的约定。

    一个WSGI服务器需要实现两个函数:

      1.解析http请求,为应用程序提供environ字典,存放请求数据

      2.实现start response函数,用于处理响应状态和响应头

    整个过程应该是这样的:
      1.从客户端获取到请求

      2.通过get_env获得environ变量

      3.调用应用程序,传入environ和start_response函数,并获得响应数据进行处理

      4.将处理后的数据返回给客户端

    在源码中是流程这样的:

      1、启动程序,app.run()调用werkezug下的run_simple方法启动服务,等待请求

      

       2、请求过来调用WSGIRequestHandler类下的handle_one_request方法开始处理请求

      

      3、run_wsgi实现三个方法: start_response返回write,write处理响应头、状态。execute启动Flask的__call__,传入environ(请求过来的原始数据)和start_response(头和状态),并接受响应数据进行处理

       

       4、execute方法就是去执行Flask

      

       5、走到这里,一个请求下来,WSGI的任务已经完成一大半,开始进入到Flask

     application_iter = app(environ, start_response)  # 调用Flask的__call__方法

      6、Flask完成的功能就是从__call__方法开始的  

      

      7、调用wsgi_app方法,创建一个ctx请求上下文管理对象

       

       8、首先看是怎样封装的原始数据environ:它重新封装一个新的request对象,让我们可以使用request.method,request.arg,request.form等方法

      

      9、封装完后,此时我们可以有我们熟悉的几个属性,封装完后的request和一个空session。

    ctx.push():

      10、创建完一个上下文管理对象后,继续往下看,走到了ctx.push,看看他做了什么,注意:这个push是RequestContext类下的push方法

      

       

      11、首先看实例一个LocalStack对象做了啥,他在初始化时实例一个Local类对象

      

       12、在看Local类在初始化做了啥:创建一个字典__storage__一个变量__ident_func__值为调用线程唯一标识的方法,实现为不同的请求创建不同的内存空间,进行数据隔离

       

       13、这时再回到RequestContext类下的push,它到底实现了什么,创建一个app上下文管理对象:app_xtc  

      

      14、看_request_ctx_stack.push(self)怎么实现的:它执行LocalStack类下的push方法,obj=ctx

      

       

       15、等到第一次有请求过来时:

    storage={
             ident:{
                   "stock":[ctx,]
              }        
         }    

      16、所以push的返回值是一个存放着ctx对象的列表,但是_request_ctx_stack.push(self)并没有接收它

      _request_ctx_stack.push(self)实现了对线程或者协程之间数据的隔离,实现原理就是创建一个storage字典,以线协程的唯一标识为key,一个字典为值,这个字典以“stock”为key,值为一个列表,存放着这个请求的上下文管理对象,例如上面的storage字典。这也就是Flask类下wsgi_app方法中ctx.push() 的实现。

    try:
        from greenlet import getcurrent as get_ident
    except:
        from threading import get_ident
    
    class Local(object):
        __slots__ = ('__storage__', '__ident_func__')
    
        def __init__(self):
            # __storage__ = {1231:{'stack':[]}}
            object.__setattr__(self, '__storage__', {})
            object.__setattr__(self, '__ident_func__', get_ident)
    
        def __getattr__(self, name):
            try:
                return self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
        def __setattr__(self, name, value):
            # name=stack
            # value=[]
            ident = self.__ident_func__()
            storage = self.__storage__
            try:
                storage[ident][name] = value
            except KeyError:
                storage[ident] = {name: value}
    
        def __delattr__(self, name):
            try:
                del self.__storage__[self.__ident_func__()][name]
            except KeyError:
                raise AttributeError(name)
    
    
    
    class LocalStack(object):
        def __init__(self):
            self._local = Local()
    
        def push(self,value):
            rv = getattr(self._local, 'stack', None) # self._local.stack =>local.getattr
            if rv is None:
                self._local.stack = rv = [] #  self._local.stack =>local.setattr
            rv.append(value) # self._local.stack.append(666)
            return rv
    
    
        def pop(self):
            """Removes the topmost item from the stack, will return the
            old value or `None` if the stack was already empty.
            """
            stack = getattr(self._local, 'stack', None)
            if stack is None:
                return None
            elif len(stack) == 1:
                return stack[-1]
            else:
                return stack.pop()
    
        def top(self):
            try:
                return self._local.stack[-1]
            except (AttributeError, IndexError):
                return None
    
    
    _request_ctx_stack = LocalStack()
    
    _request_ctx_stack.push("ctx")
    print(_request_ctx_stack.top())
    实现原理

    response = self.full_dispatch_requset():

      17、开始执行视图,看full_dispatch_request实现了什么:

      

      18、再看finalize_request方法对视图返回的数据做了怎样的处理:

      

      19、至此,full_dispatch_request方法执行完毕,它返回一个经过处理后的存有视图返回值的Respouse对象

      继续往后,到了wsgi_app的返回:return response(environ, start_response)

      它返回一个Response对象,加上括号执行BaseResponse类下的__call__方法

      

       20、至此,首尾呼应。Flask的请求流程全部完成。存放着响应体的迭代器返回给了调用Flask中__call__方法的run_wsgi下的execute方法,

       

  • 相关阅读:
    盾机
    隐藏服务器真实IP的方法来防止DDOS攻击
    EJS 是什么 ,怎么用,以及优点
    Centos7 / RHEL 7 双网卡绑定
    linux下配置双网卡及RAC规划——1
    Why React Is Favored by Front-End Specialists
    React Virtual DOM Explained in Simple English
    React Core Features
    Virtual DOM--react
    redux是全局状态(数据)的管理机制,局部数据没有意义
  • 原文地址:https://www.cnblogs.com/aizhinong/p/12741741.html
Copyright © 2011-2022 走看看