之前的文章<<WSGI介绍>>简要介绍了WSGI中的server
, application
,middleware
等概念。WSGI Server
收到请求后调用WSGI application
的入口点(一般为callable
对象或者函数)来处理请求。比如,uWSGI
和mod_wsgi
默认调用名为application的入口点。
PasteDeploy是一套发现和配置WSGI应用的系统。它根据指定的配置文件动态生成入口点和组织WSGI application
间的逻辑关系。配置文件为INI格式。每个配置文件可以包含多个section
, section
以格式为[type:name]
形式的段名开始,段名行之后为具体配置。示例如下:
1 | [DEFAULT] |
其中,[DEFAULT]
段中为全局配置,各section中可以覆盖[DEFAULT]
段中配置。如示例中的set email
配置。
常用的type有:
- app:
WSGI application
- composite: WSGI应用的组合,它可以根据规则将请求分发给不同的应用
- filter:
WSGI middleware
- pipeline: 按顺序执行的一系列
middleware
和应用
下面以示例来说明PasteDeploy的用法:
我们使用uwsgi
做为WSGI Server
,首先安装uwsgi环境:
1 | yum install -y uwsgi uwsgi-plugin-python |
安装Paste、WebOb,PasteDeploy:
1 | pip install Paste WebOb PasteDeploy |
创建三个文件:app.py, paste.ini, driver.py:
1 | mkdir wsgi && cd wsgi |
app.py内容如下:
1 | from webob import Response |
paste.ini内容如下:
1 | [app:main] |
driver.py内容如下:
1 | from paste.deploy import loadapp |
启动uwsgi加载driver.py:
1 | uwsgi --http-socket 127.0.0.1:8080 --plugins-dir /usr/lib64/uwsgi/ --plugin python_plugin.so -w driver |
打开另一终端访问8080端口,结果如下:
1 | [root@localhost src]# curl http://127.0.0.1:8080 |
下面具体各文件内容。首先来看driver.py
文件, 我们使用paste.deploy.loadapp
来动态生成名为application
的WSGI应用入口点。loadapp
参数为config:
形式的配置文件路径和以及#name
形式的section名称,比如:
1 | config:/path/to/paste.ini#start |
若没有指定名称,则使用名称为main
的section。
接下来看paste.ini。paste.ini中只包含一个app section。
section中有两种方法来指定要执行的WSGI应用。
一种是使用另外的URI或者应用名,如:
1 | [app:myapp] |
另外一种方式是直接指定需要执行的Python代码,如:
1 | [app:myapp] |
这种方式通过调用工厂函数来生成入口点。上述示例表示需要import
模块myapp.modulename
, 再调用app_factory
获取WSGI应用入口点。app_factory
的原型如下:
1 | def app_factory(global_config, **local_conf): |
global_config
是一个字典类型,存储INI配置文件中放在[DEFAULT]
section中的参数。local_conf
表示关键字参数,存储相应section侧段中参数。
下面看另一个示例。修改app.py为:
1 | from webob import Response |
再创建文件foo_filter.py,内容如下:
1 | from webob.dec import wsgify |
创建文件bar_filter.py,内容如下:
1 | from webob.dec import wsgify |
修改paste.ini为:
1 | [pipeline:main] |
重启uwsgi, 再次访问8080端口:
1 | [root@localhost src]# curl http://127.0.0.1:8080 |
首先来看foo_filter.py
,它根据req.environ[“test”]
是否存在,来直接赋值或者追加字符串”foo\n”。bar_filter.py逻辑类似。
再来看app.py, 它追加字符串”app\n”到req.environ[“test”]
, 并将该字符串做为Response返回。
paste.ini中我们使用pipeline类型来定义filter执行顺序,从结果可以看到foo_filter,bar_filter和app按我们在INI配置文件中指定的顺序来执行。我们再次修改paste.ini中的pipeline为:
1 | pipeline = bar_filter foo_filter demo |
再次访问8080端口, 看到结果顺序也跟着调整:
1 | [root@localhost src]# curl http://127.0.0.1:8080/ |
下面再以实例介绍composite
类型:
修改paste.ini为:
1 | [composite:main] |
创建文件foo_app.py,内容如下:
1 | from webob import Response |
创建bar_app.py,内容如下:
1 | from webob import Response |
重启uwsgi, 分别访问/foo
和/bar
, 结果如下:
1 | [root@localhost src]# curl http://127.0.0.1:8080/foo |
paste.ini中使用paste
包中提供的应用urlmap
根据请求的URL前缀将请求映射到不同的WSGI应用上, 这完成WEB框架的基本路由功能。
从上述几个例子,我们可以体会到PasteDeploy给WSGI应用开发带来的便利。OpenStack各项目实现都使用了PasteDeploy, 理解PasteDeploy是理解OpenStack API实现的基础。
详细说明参考官方文档: