WebOb的简单介绍
在之前的文章中我写了有关于如何使用PasteDeploy生成WSGI的Application。在Openstack的源码中,除了 PasteDeploy外,还有一个和WSGI密切相关的工具包WebOb。这篇文章就来讲讲这个WebOb。官网在 这:http://webob.org/
简单的说,WebOb是一个用于对WSGI request环境进行包装(也就是变得易用)以及用于创建WSGI response的一个包。
1.Request
webob.Request是WebOb中的一个重要对象。其会的对WSGI的environ(就是传递给WSGI APP的那个参数)参数进行封装。
一个简单的例子:
|
1
2
3
4
5
|
from webob import Requestreq = Request.blank('/article?id=1')from pprint import pprintpprint(req.environ) |
输出:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[root@OS_DEV dev]# python webobtest.py{'HTTP_HOST': 'localhost:80', 'PATH_INFO': '/article', 'QUERY_STRING': 'id=1', 'REQUEST_METHOD': 'GET', 'SCRIPT_NAME': '', 'SERVER_NAME': 'localhost', 'SERVER_PORT': '80', 'SERVER_PROTOCOL': 'HTTP/1.0', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0x7f83c59d21e0>, 'wsgi.input': <io.BytesIO object at 0x7f83c592b590>, 'wsgi.multiprocess': False, 'wsgi.multithread': False, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)} |
既然是request,那么必然有个body,并且也有request的方法(GET?POST?DELETE?),所以文档里有这么个例子:
|
1
2
3
4
5
6
7
8
9
10
|
>>> hasattr(req.body_file, 'read')True>>> req.body''>>> req.method = 'PUT'>>> req.body = 'test'>>> hasattr(req.body_file, 'read')True>>> req.body'test' |
对request请求头部的操作如下:
|
1
2
3
4
5
|
>>> req.headers['Content-Type'] = 'application/x-www-urlencoded'>>> sorted(req.headers.items())[('Content-Length', '4'), ('Content-Type', 'application/x-www-urlencoded'), ('Host', 'localhost:80')]>>> req.environ['CONTENT_TYPE']'application/x-www-urlencoded' |
对请求参数的处理如下:
|
1
2
3
4
5
6
7
8
9
|
>>> req = Request.blank('/test?check=a&check=b&name=Bob')>>> req.GETMultiDict([(u'check', u'a'), (u'check', u'b'), (u'name', u'Bob')])>>> req.GET['check']u'b'>>> req.GET.getall('check')[u'a', u'b']>>> req.GET.items()[(u'check', u'a'), (u'check', u'b'), (u'name', u'Bob')] |
下面这个是比较常见的查看参数的方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> req.paramsNestedMultiDict([(u'check', u'a'), (u'check', u'b'), (u'name', u'Bob'), (u'name', u'Joe'), (u'email', u'joe@example.com')])>>> req.params['name']u'Bob'>>> req.params.getall('name')[u'Bob', u'Joe']>>> for name, value in req.params.items():... print '%s: %r' % (name, value)check: u'a'check: u'b'name: u'Bob'name: u'Joe'email: u'joe@example.com' |
一个把request传递给WSGI应用的例子:
|
1
2
3
4
5
6
7
8
9
|
from webob import Requestreq = Request.blank('/')def wsgi_app(environ, start_response): start_response('200 OK', [('Content-type', 'text/plain')]) return ['Hi!']print req.call_application(wsgi_app) |
输出:
|
1
2
|
[root@OS_DEV dev]# python webobtest.py('200 OK', [('Content-type', 'text/plain')], ['Hi!']) |
2.Response
webob.Response包含了标准WSGI response的所有要素。其本身也可以看成是一个WSGI的application。你可以通过req.call_application(res)对其调用。
最简单的例子如下:
|
1
2
3
4
5
6
7
8
|
>>> from webob import Response>>> res = Response()>>> res.status'200 OK'>>> res.headerlist[('Content-Type', 'text/html; charset=UTF-8'), ('Content-Length', '0')]>>> res.body'' |
如何写入body:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
>>> res = Response(content_type='text/plain', charset=None)>>> f = res.body_file>>> f.write('hey')>>> f.write(u'test')Traceback (most recent call last): . . .TypeError: You can only write unicode to Response if charset has been set>>> f.encoding>>> res.charset = 'utf8'>>> f.encoding'utf8'>>> f.write(u'test')>>> res.app_iter['', 'hey', 'test']>>> res.body'heytest' |
注意下这个例子,这个例子把普通的WSGI的应用通过Request和Response做了一个简单的包装,虽然没有太大的修改,但对于之后使用装饰器的情况来说,是个不错的例子:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
>>> def my_app(environ, start_response):... req = Request(environ)... res = Response()... res.content_type = 'text/plain'... parts = []... for name, value in sorted(req.environ.items()):... parts.append('%s: %r' % (name, value))... res.body = 'n'.join(parts)... return res(environ, start_response)>>> req = Request.blank('/')>>> res = req.get_response(my_app)>>> print res200 OKContent-Type: text/plain; charset=UTF-8Content-Length: ...HTTP_HOST: 'localhost:80'PATH_INFO: '/'QUERY_STRING: ''REQUEST_METHOD: 'GET'SCRIPT_NAME: ''SERVER_NAME: 'localhost'SERVER_PORT: '80'SERVER_PROTOCOL: 'HTTP/1.0'wsgi.errors: <open file '<stderr>', mode 'w' at ...>wsgi.input: <...IO... object at ...>wsgi.multiprocess: Falsewsgi.multithread: Falsewsgi.run_once: Falsewsgi.url_scheme: 'http'wsgi.version: (1, 0) |
3.Exceptions
其实就是对HTTP错误代码的一个封装。也可以看成是一个WSGI的应用。
一个简单的例子:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> from webob.exc import *>>> exc = HTTPTemporaryRedirect(location='foo')>>> req = Request.blank('/path/to/something')>>> print str(req.get_response(exc)).strip()307 Temporary RedirectLocation: http://localhost/path/to/fooContent-Length: 126Content-Type: text/plain; charset=UTF-8307 Temporary RedirectThe resource has been moved to http://localhost/path/to/foo; you should be redirected automatically. |
4. WSGIfy decorator
结合上面的例子,既然WebOb可以让WSGI的请求变得更加简单、强大,那么能不能不用原始的那种WSGI的参数和返回格式,而全部用WebOb替代?可以的,通过WSGIfy decorator这个装饰器。
比如这个最简单的例子:
|
1
2
3
|
@wsgifydef myfunc(req): return webob.Response('hey there') |
调用的时候有两个选择:
|
1
|
app_iter = myfunc(environ, start_response) |
或:
|
1
|
resp = myfunc(req) |
第一种选择就是最原始和标准的的WSGI格式,第二种选择则是WebOb封装过后的格式。说实话后者看上去更加符合逻辑(给你个请求,给我个响应)。
如果myfanc直接返回一个Exception,那么就会的相当于直接调用Exception这个WebOb的WSGI Application,可以很容易的返回异常页面。
另外也可以对Request进行继承,修改其内容,对真正的Request做一些判断(个人感觉像是在过滤),比如:
|
1
2
3
4
5
6
7
8
9
10
|
class MyRequest(webob.Request): @property def is_local(self): return self.remote_addr == '127.0.0.1'@wsgify(RequestClass=MyRequest)def myfunc(req): if req.is_local: return Response('hi!') else: raise webob.exc.HTTPForbidden |
需要记住一点:被@wsgify修饰过后的那些func,其Return的是个对Response的调用。
5.总结
总结一下WebOb。既然有人用WebOb,那它必然有它的好用的地方,好用的地方在哪里呢?我个人觉得有两个:一是兼容性好,二是使用简单。
首先先说兼容性吧。之前写过文章介绍过PasteDeploy,后者可以通过标准的配置文件生成WSGI应用。那么通过WebOb写出的WSGI应用是否
可以用在这里呢?答案是可以的,上面的装饰器的例子已经介绍了,经过装饰器装饰后的func可以通过标准的WSGI方法去调用。
然后说说使用上的感觉。简单就是好用。其把WSGI的几个参数、返回的方法都封装成了Reqeust、Response这两个对象,同时还提供了一个好用的Exception对象,就这三个对象,记起来也不难,读起来也一看就知道是啥意思,所以说用起来方便。
个人觉得最有代表的例子是这个,一目了然,使人一读就懂。最神奇的是可以通过WSGI标准对其进行调用,写的时候完全可以忘了WSGI标准是啥,同时还能写出兼容WSGI工具(比如PasteDeploy)的代码,真是不错。
|
1
2
3
|
@wsgifydef myfunc(req): return webob.Response('hey there') |
WebOb的简单介绍的更多相关文章
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍
一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目的是为了数据分析.它提供了大量高级的数据结构和对数据处理的方法. pandas 有两个主要的数据结构 ...
- 利用Python进行数据分析(4) NumPy基础: ndarray简单介绍
一.NumPy 是什么 NumPy 是 Python 科学计算的基础包,它专为进行严格的数字处理而产生.在之前的随笔里已有更加详细的介绍,这里不再赘述. 利用 Python 进行数据分析(一)简单介绍 ...
- yii2的权限管理系统RBAC简单介绍
这里有几个概念 权限: 指用户是否可以执行哪些操作,如:编辑.发布.查看回帖 角色 比如:VIP用户组, 高级会员组,中级会员组,初级会员组 VIP用户组:发帖.回帖.删帖.浏览权限 高级会员组:发帖 ...
- angular1.x的简单介绍(二)
首先还是要强调一下DI,DI(Denpendency Injection)伸手获得,主要解决模块间的耦合关系.那么模块是又什么组成的呢?在我看来,模块的最小单位是类,多个类的组合就是模块.关于在根模块 ...
- Linux的简单介绍和常用命令的介绍
Linux的简单介绍和常用命令的介绍 本说明以Ubuntu系统为例 Ubuntu系统的安装自行百度,或者参考http://www.cnblogs.com/CoderJYF/p/6091068.html ...
- iOS-iOS开发简单介绍
概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的 ...
- iOS开发多线程篇—多线程简单介绍
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- iOS开发UI篇—UITabBarController简单介绍
iOS开发UI篇—UITabBarController简单介绍 一.简单介绍 UITabBarController和UINavigationController类似,UITabBarControlle ...
随机推荐
- Mybatis的分页查询
示例1:查询业务员的联系记录 1.控制器代码(RelationController.java) //分页列出联系记录 @RequestMapping(value="toPage/custom ...
- MVC 自定义AuthorizeAttribute 实现权限验证
MVC内置的AuthorizeFilter先于Action/Result过滤器执行,为网站权限验证提供了很好的一套验证机制. 通过自定义的AuthorizeAttribute可以实现对用户权限的验证. ...
- [itint5]任务调度
http://www.itint5.com/oj/#10 拓扑排序.首先按照题目给出的数据结构复杂度不会是O(v+e)的,所以先要变换数据结构.二来写的时候用一个stack会更好点.还有就是题目里其实 ...
- VMware 11完全安装Mac OS X 10.10
本文已迁移到我的个人网站 http://www.wshunli.com 文章地址: http://www.wshunli.com/2016/03/17/VMware-12安装Mac-OS-X-10-1 ...
- 第一章 CLR的执行模型
编译器将源代码编译为托管模块.托管木块包含: PE32或PE32+头 CLR头 元数据 IL(中间语言)代码 PE32头的文件可在32或64位的电脑上运行,PE32+的只能在64上运行.Window6 ...
- Android 签名(3)已签名的apk中的文件
已经签名 apk包中签名相关的文件在meta_INF目录下 CERT.SF:生成每个文件相对的密钥 MANIFEST.MF:数字签名信息 xxx.SF:这是JAR文件的签名文件,占位符xxx标识了签名 ...
- 摄像头(1)拍照的主要API,权限和特性,判断有没有摄像头的方法
支持 Android SDK支持操作Android设备内置的照相机.从Android2.3开始,支持操作多个摄像头(主要指前置摄像头和后置照相机).通过照相机可以拍照和录像. 注意事项 是否支持照相机 ...
- 用shell写个100以内的所有数字之和
#!/bin/bash i=2 while ((i<=100));do j=2 while ((j<=i/2));do if ((i%j==0));then break fi let j+ ...
- poj 1442 Black Box(堆 优先队列)
题目:http://poj.org/problem?id=1442 题意:n,m,分别是a数组,u数组的个数,u[i]w为几,就加到a几,然后输出第i 小的 刚开始用了一个小顶堆,超时,后来看了看别人 ...
- struts2启动报错com/opensymphony/xwork2/spring/SpringObjectFactory.java:220:-1
好久没有搞struts2,今天配置strut2.2.1,启动时遇到个小问题.记录下. tomcat启动报错: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ...