还记得在上面创建WSGI Server的时候,传入了一个 self.app 参数,这个app并不是一个固定的app,而是使用 PasteDeploy 中提供的 loadapp 函数从 paste.ini 配置文件中加载application。
具体可以,看下nova的实现。
通过打印的 DEBUG 内容得知 config_url 和 app name 的值
app: osapi_compute config_url: /etc/nova/api-paste.inia通过查看 /etc/nova/api-paste.ini ,在 composite 段里找到了 osapi_compute 这个app(这里的app和wsgi app 是两个概念,需要注意区分) ,可以看出 nova 目前有两个版本的api,一个是 v2,一个是v2.1,目前我们在用的是 v2.1,从配置文件中,可以得到其指定的 application 的路径是nova.api.openstack.compute 这个模块下的 APIRouterV21 类 的factory方法,这是一个工厂函数,返回 APIRouterV21 实例。
[composite:osapi_compute] use = call:nova.api.openstack.urlmap:urlmap_factory /: oscomputeversions /v2: openstack_compute_api_v21_legacy_v2_compatible /v2.1: openstack_compute_api_v21 [app:osapi_compute_app_v21] paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory这是 OpenStack 使用 PasteDeploy 实现的第一层的路由,如果你不感兴趣,可以直接略过本节,进入下一节,下一节是 介绍 PasteDeploy 的使用,教你实现一个简易的web server demo。推荐一定要看。
06. PasteDeploy 使用说明到上一步,我已经得到了 application 的有用的线索。考虑到很多人是第一次接触 PasteDeploy,所以这里结合网上博客做了下总结。对你入门会有帮助。
掌握 PasteDeploy ,你只要按照以下三个步骤逐个完成即可。
1、配置 PasteDeploy使用的ini文件;
2、定义WSGI应用;
3、通过loadapp函数加载WSGI应用;
第一步:写 paste.ini 文件
在写之前,咱得知道 ini 文件的格式吧。
首先,像下面这样一个段叫做 section。
[type:name] key = value ...其上的type,主要有如下几种
composite (组合):多个app的路由分发;
[composite:main] use = egg:Paste#urlmap / = home /blog = blog /wiki = wiki
app(应用):指明 WSGI 应用的路径;
[app:home] paste.app_factory = example:Home.factory
pipeline(管道):给一个 app 绑定多个过滤器。将多个filter和最后一个WSGI应用串联起来。
[pipeline:main] pipeline = filter1 filter2 filter3 myapp [filter:filter1] ... [filter:filter2] ... [app:myapp] ...
filter(过滤器):以 app 做为唯一参数的函数,并返回一个“过滤”后的app。通过键值next可以指定需要将请求传递给谁。next指定的可以是一个普通的WSGI应用,也可以是另一个过滤器。虽然名称上是过滤器,但是功能上不局限于过滤功能,可以是其它功能,例如日志功能,即将认为重要的请求数据记录下来。
[app-filter:filter_name] use = egg:... next = next_app [app:next_app] ...对 ini 文件有了一定的了解后,就可以看懂下面这个 ini 配置文件了
[composite:main] use = egg:Paste#urlmap /blog = blog /wiki = wiki [app:blog] paste.app_factory = example:Blog.factory [app:wiki] paste.app_factory = example:Wiki.factory第二步是定义一个符合 WSGI 规范的 applicaiton 对象。
符合 WSGI 规范的 application 对象,可以有多种形式,函数,方法,类,实例对象。这里仅以实例对象为例(需要实现 __call__ 方法),做一个演示。
import os from paste import deploy from wsgiref.simple_server import make_server class Blog(object): def __init__(self): print("Init Blog.") def __call__(self, environ, start_response): status_code = "200 OK" response_headers = [("Content-Type", "text/plain")] response_body = "This is Blog's response body.".encode('utf-8') start_response(status_code, response_headers) return [response_body] @classmethod def factory(cls, global_conf, **kwargs): print("Blog factory.") return Blog()最后,第三步是使用 loadapp 函数加载 WSGI 应用。
loadapp 是 PasteDeploy 提供的一个函数,使用它可以很方便地从第一步的ini配置文件里加载 app
loadapp 函数可以接收两个实参:
URI:"config:"
name:WSGI应用的名称
conf_path = os.path.abspath('paste.ini') # 加载 app applications = deploy.loadapp("config:{}".format(conf_path) , "main") # 启动 server, 监听 localhost:22800 server = make_server("localhost", "22800", applications) server.serve_forever()applications 是URLMap 对象。
完善并整合第二步和第三步的内容,写成一个 Python 文件(wsgi_server.py)。内容如下
import os from paste import deploy from wsgiref.simple_server import make_server class Blog(object): def __init__(self): print("Init Blog.") def __call__(self, environ, start_response): status_code = "200 OK" response_headers = [("Content-Type", "text/plain")] response_body = "This is Blog's response body.".encode('utf-8') start_response(status_code, response_headers) return [response_body] @classmethod def factory(cls, global_conf, **kwargs): print("Blog factory.") return Blog() class Wiki(object): def __init__(self): print("Init Wiki.") def __call__(self, environ, start_response): status_code = "200 OK" response_headers = [("Content-Type", "text/plain")] response_body = "This is Wiki's response body.".encode('utf-8') start_response(status_code, response_headers) return [response_body] @classmethod def factory(cls, global_conf, **kwargs): print("Wiki factory.") return Wiki() if __name__ == "__main__": app = "main" port = 22800 conf_path = os.path.abspath('paste.ini') # 加载 app applications = deploy.loadapp("config:{}".format(conf_path) , app) server = make_server("localhost", port, applications) print('Started web server at port {}'.format(port)) server.serve_forever()一切都准备好后,在终端执行 python wsgi_server.py来启动 web server
如果像上图一样一切正常,那么打开浏览器
访问:8000/blog,应该显示:This is Blog's response body.
访问:8000/wiki,应该显示:This is Wiki's response body.。
注意:urlmap对url的大小写是敏感的,例如如果访问:8000/BLOG,在url映射中未能找到大写的BLOG。
到此,你学会了使用 PasteDeploy 的简单使用。
07. webob.dec.wsgify 装饰器