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

五、Request的更多相关文章

  1. jsp内置对象request 和response

    1.request对象主要用于处理客户端的请求 request对象常用方法 一.String  request.getParameter(String name)             根据页面表单 ...

  2. Django视图层、虚拟环境

    一.虚拟环境安装 目的:为了解决版本共存问题 ''' 1.通过pip3安装虚拟环境: -- pip3 install virtualenv 2.前往目标文件夹: -- cd 目标文件夹 (C:\Vir ...

  3. Django基础三之视图函数

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

  4. javaWeb_Request对象

    首先说一下Http协议 一.Http协议的概念及作用 1.什么是HTTP协议? (HTTP,HyperText Transfer Protocol)超文本传输协议, 是互联网上应用最为广泛的一种网络协 ...

  5. Django - 表与ORM操作

    Django - 表与ORM操作 一. 模板语言 模板中也有自己的语言, 该语言可以实现数据展示 - {{ 变量 }} - 循环 {% for i in all_publisher %} {{ for ...

  6. 03.Django基础三之视图函数

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

  7. 03 Django之视图函数

    一.Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python函数(类),它接受WEB请求并返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...

  8. day 53-1 Django基础三之视图函数

    Django基础三之视图函数   本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...

  9. day 67 Django基础三之视图函数

    Django基础三之视图函数   本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...

  10. view架构

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

随机推荐

  1. Drupal7_2:安装drupal

    Drupal7_2:安装drupal 分类: Drupal72012-10-30 01:06 1074人阅读 评论(0) 收藏 举报 假设你已经搭建好了所需的必备环境,接下来就参照以下几步,快速安装一 ...

  2. 所有文章都迁移到我自己的博客了:http://blog.neazor.com

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  3. Net框架下-ORM框架LLBLGen的简介

    >对于应用程序行业领域来说,涉及到Net框架的,在众多支持大型项目的商用ORM框架中,使用最多的目前了解的主要有三款: 1.NHibernate(从Java版移植来的Net版). 2.微软的EF ...

  4. swift 如何删除subviews

    scrollView.subviews.map { (var view) -> () in if (view is UIButton) { view.removeFromSuperview() ...

  5. iOS:缓存与Operation优先级问题

    这篇博客来源于今年的一个面试题,当我们使用SDWebImgae框架中的sd_setImageWithURL: placeholderImage:方法在tableView或者collectionView ...

  6. 在spring,mybatis整合配置中走的弯路(1)

    在接触一个新东西,总免不了走一些弯路,也正是在这些弯路中,我们不断的成长. 从git上把之前写的代码扒下来,看看我在当初使用spring与mybatis中所走的弯路,路过的君子也可引以为戒. < ...

  7. Spring3系列9- Spring AOP——Advice

    Spring3系列9- Spring AOP——Advice Spring AOP即Aspect-oriented programming,面向切面编程,是作为面向对象编程的一种补充,专门用于处理系统 ...

  8. 解决oracle 端口 1521 本机127可通 其他ip不通

    http://wenku.baidu.com/link?url=8tRGGObqgLd6-yqprioIZSyluu9K0BgA29Lhx7F57pVDIHbMHVDNTa_SlEmVugGT4QJO ...

  9. JIT

    http://www.cppblog.com/vczh/category/9583.html

  10. reinstall_xbt: Linux中如何查看文件的最初创建时间

    Linux中如何查看文件的最初创建时间 与文件相关的几个时间: 1.访问时间,读一次这个文件的内容,这个时间就会更新.比如对这个文件使用more命令.ls.stat命令都不会修改文件的访问时间.   ...