通过上文的讨论,我们已经对WSGI有了一点认识了,那么现在,就让我们大体上认识一下Webob吧!
什么是Webob?
WSGI是故意设计成最小的Web服务器实现轻松的应用,以便被更多的人采用。但是,几乎没有人真的喜欢直接操作
environ
变量,也几乎没有人喜欢用start_response
这么诡异的逻辑,虽然WSGI提供的API易于实现,但这不代表它的语义让人满意。也正是因为这一原因,几乎每一个应用程序或者web框架都把environ
和start_response
封装成了语义更完善容错率更高的request和response对象。Webob就是request
和response
对象的规范实现之一,它使得WSGI更容易和更满意地被大家使用
Webob: request & response 对象
Webob.Request
类封装了environ
,我们可以很方便的做任何事请,废话不多,上栗子。
from webob import Request
request = Request(environ)
path_info = request.path_info
form_param = request.params["form_param"]
Webob.Response
类,它让在语义上表现的更像一个HTTP
响应,它实例化出对象都是WSGI可调用的,这些实例化出来的响应对象可以帮我们处理start_response
这个异端,同样,栗子。
from webob import Response
response = Response("Hello World!", "200 OK", [
("Content-type", "text/plain"),
])
return response(environ, start_response)
看,就是这样,依然是超轻量级,不过语义上却更友善了。接下来,就让我们试试用Webob来改写我们之前的某个栗子吧:
def __call__(self, environ, start_response):
''' WSGI entry point
'''
request = Request(environ)
response = self._service(request)
return response(environ, start_response)
def _service(self, request):
assert isinstance(request, Request)
path_info = request.path_info
if not path_info:
return request.get_response(self.application)
注意,虽然上述栗子中并没有用到Response
类,但是在_service
方法中调用了get_response()
,它们是否起到了相同的作用呢?
当然,上面的栗子只是在整体逻辑上概述了一下如何用Webob代替原生WSGI,也就是说,我们一般在实际开发的过程中并不这么用,为什么(?),因为这还不够优雅。那么,怎么才算得上优雅呢?
使用装饰器模式通过Webob封装WSGI入口
对,没错,你可能已经猜到了,就是装饰器。那么,作为奖励,我给你个栗子:
def wsgi_app(func):
def wrapper(environ, start_response):
request = Request(environ)
response = func(request)
return response(environ, start_response)
@wsgi_app
def app(resquest):
body = html % (dict_to_string(request.params),
dict_to_string(request.environ))
return Response(body=body,
headerlist=[
("Content-type", "text/html"),
("Content-length", str(len(body))),
])
这样呢,以后你在想把某个app
变成WSGI的application
的时候,就可以直接用wsgi_app
装饰器进行装饰就ok了,很优雅,不是吗?
ps:终于要到重头戏了,下次,我们将开始步入 openstack 正题,来讨论讨论PasteDeploy
吧 :)