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. 和View Controllers一起工作

    在这一课中,你会继续在FoodTracker菜谱的场景工作.你会重新安排现有的UI元素并使用图像采集器添加到照片用户界面.当你完成,你的应用程序将是这个样子: 学习目标 在课程结束时,你将能够: 了解 ...

  2. 深入了解STL中set与hash_set,hash表基础

    一,set和hash_set简介 在STL中,set是以红黑树(RB-Tree)作为底层数据结构的,hash_set是以哈希表(Hash table)作为底层数据结构的.set可以在时间复杂度为O(l ...

  3. 频域分辨率与DFT,DCT,MDCT理解

    搞了这么久音频算法,有些细节还没有很清楚. 比如DFT和DCT有哪些区别,DFT系数为什么会是对称的,同样帧长的数据,各自的频域分辨率是多少? 今天决定搞清楚这些问题, 首先DFT的系数对称(2N点的 ...

  4. jQuery Mobile 移动开发中的日期插件Mobiscroll使用说明

    近期在移动方面的开发,使用jQuery Mobile ,移动方面的插件不如Web 方面的插件多,选择的更少,有一些需要自己去封装,但功力尚不足啊. 日期插件JQM也提供了内置的,但样式方面不好看,只好 ...

  5. Apache Internal Server Error

    当使用 Apache 作为服务器,使用 cgi 程序接收来自 web 端的访问时,出现如下错误: Internal Server Error The server encountered an int ...

  6. Sencha Touch+PhoneGap打造超级奶爸之喂养记(一) 源码免费提供

    起源 非常高兴我的宝宝健康平安的出生了.对于初次做奶爸的我,喜悦过后,面临着各中担心,担心宝宝各项指标是否正常.最初几天都是在医院待着,从出生那一天开始,护士妹妹隔一段时间就会来问宝宝的喂奶,大小便, ...

  7. CSS - toggle collapse 类似bootstrap的展开效果

    问题:toggle collapse 类似bootstrap的展开效果(展开一个关闭另一个) Demo:http://jsfiddle.net/JSDavi/L47vscw4/ 方案:使用transi ...

  8. Unity不同平台生成中预处理的注意点

    http://blog.csdn.net/pandawuwyj/article/details/7959335 Unity3D的项目,这周吃亏在宏上了.大背景是项目需要在Unity中用Hudson自动 ...

  9. DiskGenius无损调整分区大小

    一般情况下,调整分区的大小,通常都涉及到两个或两个以上的分区.比如,要想将某分区的大小扩大,通常还要同时将另一个分区的大小缩小:要想将某个分区的大小缩小,则通常还要同时将另一个分区的大小扩大.    ...

  10. 移动API-restful的设计原则和参考

    移动应用API设计10大技巧 http://jingyan.baidu.com/article/455a9950fd27ffa166277825.html RESTful API 设计指南 http: ...