五、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
五、Request的更多相关文章
- jsp内置对象request 和response
1.request对象主要用于处理客户端的请求 request对象常用方法 一.String request.getParameter(String name) 根据页面表单 ...
- Django视图层、虚拟环境
一.虚拟环境安装 目的:为了解决版本共存问题 ''' 1.通过pip3安装虚拟环境: -- pip3 install virtualenv 2.前往目标文件夹: -- cd 目标文件夹 (C:\Vir ...
- Django基础三之视图函数
一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...
- javaWeb_Request对象
首先说一下Http协议 一.Http协议的概念及作用 1.什么是HTTP协议? (HTTP,HyperText Transfer Protocol)超文本传输协议, 是互联网上应用最为广泛的一种网络协 ...
- Django - 表与ORM操作
Django - 表与ORM操作 一. 模板语言 模板中也有自己的语言, 该语言可以实现数据展示 - {{ 变量 }} - 循环 {% for i in all_publisher %} {{ for ...
- 03.Django基础三之视图函数
一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...
- 03 Django之视图函数
一.Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python函数(类),它接受WEB请求并返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...
- day 53-1 Django基础三之视图函数
Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...
- day 67 Django基础三之视图函数
Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...
- view架构
一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...
随机推荐
- 和View Controllers一起工作
在这一课中,你会继续在FoodTracker菜谱的场景工作.你会重新安排现有的UI元素并使用图像采集器添加到照片用户界面.当你完成,你的应用程序将是这个样子: 学习目标 在课程结束时,你将能够: 了解 ...
- 深入了解STL中set与hash_set,hash表基础
一,set和hash_set简介 在STL中,set是以红黑树(RB-Tree)作为底层数据结构的,hash_set是以哈希表(Hash table)作为底层数据结构的.set可以在时间复杂度为O(l ...
- 频域分辨率与DFT,DCT,MDCT理解
搞了这么久音频算法,有些细节还没有很清楚. 比如DFT和DCT有哪些区别,DFT系数为什么会是对称的,同样帧长的数据,各自的频域分辨率是多少? 今天决定搞清楚这些问题, 首先DFT的系数对称(2N点的 ...
- jQuery Mobile 移动开发中的日期插件Mobiscroll使用说明
近期在移动方面的开发,使用jQuery Mobile ,移动方面的插件不如Web 方面的插件多,选择的更少,有一些需要自己去封装,但功力尚不足啊. 日期插件JQM也提供了内置的,但样式方面不好看,只好 ...
- Apache Internal Server Error
当使用 Apache 作为服务器,使用 cgi 程序接收来自 web 端的访问时,出现如下错误: Internal Server Error The server encountered an int ...
- Sencha Touch+PhoneGap打造超级奶爸之喂养记(一) 源码免费提供
起源 非常高兴我的宝宝健康平安的出生了.对于初次做奶爸的我,喜悦过后,面临着各中担心,担心宝宝各项指标是否正常.最初几天都是在医院待着,从出生那一天开始,护士妹妹隔一段时间就会来问宝宝的喂奶,大小便, ...
- CSS - toggle collapse 类似bootstrap的展开效果
问题:toggle collapse 类似bootstrap的展开效果(展开一个关闭另一个) Demo:http://jsfiddle.net/JSDavi/L47vscw4/ 方案:使用transi ...
- Unity不同平台生成中预处理的注意点
http://blog.csdn.net/pandawuwyj/article/details/7959335 Unity3D的项目,这周吃亏在宏上了.大背景是项目需要在Unity中用Hudson自动 ...
- DiskGenius无损调整分区大小
一般情况下,调整分区的大小,通常都涉及到两个或两个以上的分区.比如,要想将某分区的大小扩大,通常还要同时将另一个分区的大小缩小:要想将某个分区的大小缩小,则通常还要同时将另一个分区的大小扩大. ...
- 移动API-restful的设计原则和参考
移动应用API设计10大技巧 http://jingyan.baidu.com/article/455a9950fd27ffa166277825.html RESTful API 设计指南 http: ...