博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何使用Paste.Deploy
阅读量:6243 次
发布时间:2019-06-22

本文共 6998 字,大约阅读时间需要 23 分钟。

转自:http://bingotree.cn/?p=100

1.Paste Deploy的一个组件,但是并不依赖于Paste的其它组件。其可以看成是一个独立的包。其主要用于通过一个配置文件完成WSGI应用和服务器的构建。对于一个不怎么了解Python的人来说,只要知道了这个配置文件如何编写,那么也能写出一个符合WSGI标准的应用。这样说可能还是有点抽象,下面看了例子就清楚了。

2.安装PasteDeploy

1
2
3
[root@OS_DEV ~]# pip install PasteDeploy
Requirement already satisfied (use --upgrade to upgrade): PasteDeploy in /usr/lib/python2.6/site-packages
Cleaning up...

3.配置文件

这个是官网的一个配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki
/cms = config:cms.ini
 
[app:home]
use = egg:Paste#static
document_root = %(here)s/htdocs
 
[filter-app:blog]
use = egg:Authentication#auth
next = blogapp
roles = admin
htpasswd = /home/me/users.htpasswd
 
[app:blogapp]
use = egg:BlogApp
database = sqlite:/home/me/blog.db
 
[app:wiki]
use = call:mywiki.main:application
database = sqlite:/home/me/wiki.db

首先,配置文件分为多个section,每个section的名字的格式是TYPE:NAME,每个section中参数的格式一般是KEY = VALUE。我们分别来看看各种TYPE:

3.1 TYPE = composite

1
2
3
4
5
6
[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki
/cms = config:cms.ini

composite这个类型的section会的把具体的URL请求分配到VALUE对应的section中的APP上去。use表明具体的分配方 法,换句话说这里的KEY = VALUE是egg:Paste#urlmap这个Python模块的参数,个人猜测egg:Paste#urlmap的实现应该类似于:

1
2
3
if
(URL
=
=
"/"
) call(home_app)
if
(URL
=
=
"/blog"
) call(wiki)
if
(URL
=
=
"/cms"
) call(config:cms.ini)

3.2 TYPE = app

1
2
3
[app:home]
use = egg:Paste#static
document_root = %(here)s/htdocs

一个app就是一个具体的WSGI的应用。具体调用那个python module中的app则由use来指定。use有很多类型,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[app:myapp]
use = config:another_config_file.ini#app_name
 
# or any URI:
[app:myotherapp]
use = egg:MyApp
 
# or a callable from a module:
[app:mythirdapp]
use = call:my.project:myapplication
 
# or even another section:
[app:mylastapp]
use = myotherapp

其实也不难,大概看看就知道每种的含义了。config:another_config_file.ini#app_name表示从另外一个 config.ini文件中找app。egg:MyApp是从python蛋中找。call:my.project:myapplication是直接调 用某个模块中的myapplication。use = myotherapp则是在其它section找app。

另外还有一种调用方法:

1
2
[app:myapp]
paste.app_factory = myapp.modulename:app_factory

这里直接指定了使用myapp.modulename中的app_factory作为我们的app。paste.app_factory表明表明了我们的app_factory所使用的格式,app_factory的相关格式、参数、返回值我们下面会讲到。

另外在section中的其它KEY = VALUE对则是会的被当成参数传到我们的app中。

3.3 TYPE = filter-app

1
2
3
4
5
6
7
8
9
[filter-app:blog]
use = egg:Authentication#auth
next = blogapp
roles = admin
htpasswd = /home/me/users.htpasswd
 
[app:blogapp]
use = egg:BlogApp
database = sqlite:/home/me/blog.db

filter-app就是一个过滤,也就是说一个请求过来后,会的先走filter-app中的use指定的app,如果那个app过滤了这个 request,那么这个request就不会发送到next指定的app中去进行下一步处理了。如果没有过滤,则会发送给next指定的app。这个 filter-app虽然有过滤的名字,但其实也不一定要做过滤这档子事情,可以用来记录些日志啥的,比如每次来个请求就log些东西,然后再转给后面的 app去处理。fiter-app必须要有next,这个和filter不一样

3.4 TYPE = filter

1
2
3
4
5
6
7
[app:main]
use = egg:MyEgg
filter-with = printdebug
 
[filter:printdebug]
use = egg:Paste#printdebug
# and you could have another filter-with here, and so on...

和filter-app差不多,但是没有next

3.5 TYPE = pipeline

1
2
3
4
5
[pipeline:main]
pipeline = filter1 egg:FilterEgg#filter2 filter3 app
 
[filter:filter1]
...

pipeline就是简化了filter-app,不然你想,如果我有十个filter,那不是要写十个filter-app,然后用next连起 来?所以通过pipeline,我就可以把这些filter都连起来写在一行,很方便。但要注意的是这些filter需要有一个app作为结尾。

4.基本用法

如何使用呢?很简单。我们都说了,这个Paste Deploy就是为了从配置文件生成一个WSGI的APP,所以只要这样调用就行了:

1
2
from
paste.deploy
import
loadapp
wsgi_app
=
loadapp(
'config:/path/to/config.ini'
)

5.全局section

这个很好理解,看个例子:

1
2
3
4
5
6
[DEFAULT]
admin_email = webmaster@example.com
 
[app:main]
use = ...
set admin_email = bob@example.com

main这个app里会有一个参数admin_email传递进去,默认就是DEFAULT中的那个,当然可以通过set来覆盖。

6.具体的factory格式

PasteDeploy自身有很多的factory,这些factory对普通的WSGI标准做了个封装,让用的时候好用一些。我们来看看对应的格式:
6.1 paste.app_factory

1
2
def
app_factory(global_config,
*
*
local_conf):
    
return
wsgi_app

这个比较简单,写的时候就是只要写一个我们需要的WSGI_APP就行了。

6.2 paste.composite_factory

1
2
def
composite_factory(loader, global_config,
*
*
local_conf):
    
return
wsgi_app

这个其实就是比上面多了个loader方法,loader有get_app之类的方法。

6.3 paste.filter_factory

类似于paste.app_factory。和app_factory的区别在于paste.filter_factory返回的是一个filter。filter究竟是个啥?其实很简单,无非就是个if-else,比如:

1
2
if ("一切ok,没啥可以过滤的") return NEXT_WSGI_APP(XXX)
else return "直接返回WSGI的标准返回报文,request请求链在这里就断了"

这个是个形象的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def
auth_filter_factory(global_conf, req_usernames):
    
# space-separated list of usernames:
    
req_usernames
=
req_usernames.split()
    
def
filter
(app):
        
return
AuthFilter(app, req_usernames)
    
return
filter
 
class
AuthFilter(
object
):
    
def
__init__(
self
, app, req_usernames):
        
self
.app
=
app
        
self
.req_usernames
=
req_usernames
 
    
def
__call__(
self
, environ, start_response):
        
if
environ.get(
'REMOTE_USER'
)
in
self
.req_usernames:
            
return
self
.app(environ, start_response)
        
start_response(
            
'403 Forbidden'
, [(
'Content-type'
,
'text/html'
)])
        
return
[
'You are forbidden to view this resource'
]

换句话说,auth_filter_factory需要有一个filter的方法,假设有两个filter,那么Paste Deploy可能会生成这样的代码:

1
2
APP = filter01(WSGI_APP) = AuthFilter01
APP02 = filter02(AuthFilter01) = AuthFilter02

实际上调用的时候变成:

APP02(XXX,XXX),也就是AuthFilter02(XXX,XXX),而AuthFilter02会的先做过滤,如果过滤成功,那么直接由 他返回我们的HTTP报文,否则调用AuthFilter01,AuthFilter01也会做个过滤,如果过滤成功,则返回HTTP报文,否则调用最后 的WSGI_APP。

因此如果写在pipeline中,那么顺序就应该是:filter02 filter01 WSGI_APP

6.4 paste.filter_app_factory

这个的话就是把paste.filter_factory从function变成了class,原理是一样的。

6.5 paste.server_factory

生成一个WSGI标准的SERVER:

1
2
3
4
5
6
def
server_factory(global_conf, host, port):
    
port
=
int
(port)
    
def
serve(app):
        
s
=
Server(app, host
=
host, port
=
port)
        
s.serve_forever()
    
return
serve

这里的Server可以自由选择。

7.总结

说了这么多,来个总结吧。如果说我有一个pipeline是这个样子滴:

1
pipeline = filter01 filter02 app

filter01对应的是TEST:filter01_factory

filter02对应的是TEST:filter02_factory
app对应的是TEST:app_factory

相关的代码可以是:

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
32
33
34
def
filter01_factory(global_conf, XXX):
    
def
filter
(app):
        
return
Filter01(app)
    
return
filter
 
class
Filter01(
object
):
    
def
__init__(
self
, app,):
        
self
.app
=
app
 
    
def
__call__(
self
, environ, start_response):
        
if
"满足某个条件"
:
            
return
self
.app(environ, start_response)
        
start_response(
            
'403 Forbidden'
, [(
'Content-type'
,
'text/html'
)])
        
return
[
'You are forbidden to view this resource'
]
 
def
filter02_factory(global_conf, XXX):
    
def
filter
(app):
        
return
Filter02(app)
    
return
filter
 
class
Filter02(
object
):
    
def
__init__(
self
, app,):
        
self
.app
=
app
 
    
def
__call__(
self
, environ, start_response):
        
if
"满足某个条件"
:
            
return
self
.app(environ, start_response)
        
start_response(
            
'403 Forbidden'
, [(
'Content-type'
,
'text/html'
)])
        
return
[
'You are forbidden to view this resource'
]
 
def
app_factory(global_config,
*
*
local_conf):
    
return
WSGI_APP
#一个真正干活的的WSGI APP,符合WSGI的标准

那么根据上面的总结,paste会的生成如下的代码:

 

1
2
3
4
5
6
7
8
WSGI_APP
=
app_factory(XXX)
FILTER01
=
filter01_factory(XXX)
FILTER02
=
filter02_factory(XXX)
 
CALLABLE_WSGI_APP
=
FILTER02(FILTER01(WSGI_APP))
#实际的请求格式会的是CALLABLE_WSGI_APP(XXX,XXX),这里的CALLABLE_WSGI_APP实际上变成了Filter02
 
s
=
Server(CALLABLE_WSGI_APP, host
=
host, port
=
port)
s.serve_forever()

转载于:https://www.cnblogs.com/zmlctt/p/4208924.html

你可能感兴趣的文章
阿里钉钉VS企业微信 谁才是企业级一哥?
查看>>
2015-2020智慧城市物联网市场复合年增长率达23.2%
查看>>
做好数据分析让物联网数据价值最大化
查看>>
OpenStack Days走进北京 主角是用户
查看>>
JVM问题诊断常用命令:jinfo,jmap,jstack
查看>>
叶成辉成神州控股新任CEO 曾在IBM/EMC任职
查看>>
中小企业客户营收增长将成微博2016年主推动力
查看>>
四川能投成功进军智慧城市投资市场
查看>>
雅虎公开三封收到的FBI国家安全信函
查看>>
云计算在大数据形式下的发展
查看>>
如何更好地进行机房项目的控制成本
查看>>
爱立信高通中兴等成立Avanci专利授权平台 旨在加速物联网发展
查看>>
美情报公司:勒索病毒WannaCry的创作者可能是中国人
查看>>
华科技:以市场为导向 以用户体验为标准
查看>>
诺基亚携手Facebook联合开展跨大西洋现场测试
查看>>
如何检查MySQL数据库的主从延时?
查看>>
红炜:改变光伏电站融资难也需水到渠成
查看>>
三星用户迎利好 三星将推月度安全更新
查看>>
网络时代安全问题凸显 互联网金融如何有效避开痛点?
查看>>
移动OA如何治愈外出办公“焦虑症”?
查看>>