花了两个星期,我终于把 WSGI 整明白了 (3)

还记得在上面创建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 装饰器

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwppjj.html