zoukankan      html  css  js  c++  java
  • 五、Request

    1.      Request

    由于python函数所有变量都没有显示类型声明,特别是函数的输入参数,输出参数,因此在阅读代码时会造成比较大的困扰,比如大部分处理函数都有request输入参数,不同模块的的request对于的类型不同,比如在socketserver.py模块,request就是一个_socketobject实体,在WSGIHandler里面是WSGIRequest(HTTPRequest)实体。

    Django中对到来的http请求数据进行解析和缓存的数据流程如下图所示。

     

    在上图中,WSGIServer在process_request()成员函数中调用self.get_request()返回[request, clientAddr],这里的request仅仅是一个_socketobject类实体,[request, clientAddr]作为入参,初始化WSGIRequestHandler,在WSGIRequestHandler模块,首先根据reqeust(socket),创建输入输出缓冲区rfile和wfile,然后对http头部进行一些基本的解析操作,解析的结果保存到self.command,self.version,self.path等成员变量。解析主要通过下面几个调用实现:

    self.raw_requestline = self.rfile.readline(65537)
    self.parse_request()
    self.get_environ()

           其中get_environ()将解析到的头部信息,通过字典的形式保存起来并作为ServerHandler的输入参数之一,这样ServerHandler初始化后的实体base_env获得了这些环境变量信息(头部信息)。ServerHandler共有三个变量[os_environ, base_env, environ]来保存环境变量,其中os_environ保存系统的参数,如程序运行的主机参数等,base_env即ServerHandler初始化时由上层(WSGIRequestHandler)传递过来的HTTP头部请求参数,environ在[os_environ, base_env]基础上添加部分WSGI参数构成。

        ServerHandler.run(application)à application(self.environ, self.start_response)

           通过上述调用,environ直接传递给WSGIHandler,而在WSGIHandler模块里面,直接将environ再次传递给了WSGIRequest实体。

             request = WSGIHandler.request_class(environ)

    1.1       HTTP body解析

    对于POST操作,通常需要在HTTP body里携带用户信息,这些用户信息是何时去读取?何时去解析?最终保存到哪里呢?保存的格式又是怎么样的呢?

    Django对HTTP body的解析是分为两步走策略,第一步,设置环境变量,设置回调函数等,为读取body做准备;第二步,在对这些body信息进行引用时,才会去调用设置的回调函数来读取和解析body参数。这中机制能够做到开销最小化——只有在需要对body信息进行引用时才进行读取和解析。

    第一步、设置回调函数,设置环境变量

    1、class WSGIRequest(http.HttpRequest)定义的最后两行语句独立于所有其他成员函数,因此这两行命令在加载(import)WSGIRequest时,或者在加载(import)引用WSGIRequest的类时进行执行。
    POST = property(_get_post, _set_post)
    FILES = property(_get_files)

    事实上,因为WSGIHandler类引用了WSGIRequest类,因此在执行如下命令时,会执行上面两条命令:

    from django.core.handlers.wsgi import WSGIHandler

    而这条命令通常会在初始化django应用时即得到执行。显然,这种命令应该是静态命令,与程序执行前后的上下文无关,事实上,也只是对部分接口进行装饰,这样,后续,对

    request.POST.get()/request.POST.set()操作时,实际上调用的是request. _get_post()/request. _set_post()的操作。request.FILES.get()也是如此。

    2、对于到来的HTTP请求,Django在初始化WSGIRequest(HTTPRquest)实体时,对头部信息进行简单解析和继承(因为在前面的WSGIRequestHandler阶段已经进行了一定程度的绩溪),在解析到content_length后,初始化一个stream实体,为后续读取body

    self._stream = LimitedStream(self.environ['wsgi.input'], content_length)

    同样,LimitedStream()定义了自己的read(),readline()接口。

    第二步、引用触发读取和解析过程。

    在设置回调函数完毕之后,后续模块(中间件模块,handler模块等)如果需要对http body进行引用,就会触发读取和解析过程。例如,在csrfmidlerware中间件中如下调用会触发读取和解析操作:

    request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')

    request.POST.get重定向到WSGIRequest:_get_post()-->

       if not hasattr(self, '_post'):  /*如果前面已经对body读取和解析了,会填充该成员变量*/

          self._load_post_and_files()       /*读取http body 并解析*/

       return self._post         /*前面已经对body读取和解析了,直接返回 */

    HttpRequest: _load_post_and_files()-->

      if self.content_type == 'multipart/form-data':

    self._post, self._files = self.parse_file_upload(self.META, data)

      elif self.content_type == 'application/x-www-form-urlencoded':

    self._post, self._files = QueryDict(self.body, encoding=self._encoding), MultiValueDict()

      else:

    self._post, self._files = QueryDict(encoding=self._encoding), MultiValueDict()

    可见,Django只对multipart/form-data和application/x-www-form-urlencoded格式的http-body进行了解析,并将解析的结果以QueryDict的格式保存在self._post中,其余格式也保存在self._post中,但是并没有解析。如果需要添加django对json解析,在此次添加也不失为一种好策略。

    另外,需要注意QueryDict的输入参数之一self.body,它完成对body数据的读取,并以字符的形式保存一个副本。

    HttpRequest: body()-->

      if self._read_started:

    raise RawPostDataException()

    /*读取http body,此时的self._stream 指向第一步设置的LimitedStream 实体*/

      self._body = self.read()àreturn self._stream.read(*args, **kwargs)

      self._stream = BytesIO(self._body)  /*读取完毕之后恢复stream为指向self._body ,便于后续处理*/

      return self._body

  • 相关阅读:
    复制表结构及数据
    mysql 字段名是关键字 报错
    mysql 截取字符串
    《官方资料》 例如:string 函数 、分组函数
    mysql event 入门
    Spring国际化
    Python学习记录
    精选股文
    为VS定制一个自己的代码生成器
    房产常识
  • 原文地址:https://www.cnblogs.com/fbli/p/5925082.html
Copyright © 2011-2022 走看看