原创作品,转载注明本文出处:http://www.cnblogs.com/Security-Darren/p/4087587.html

  

  谈到WSGI,就免不了要了解paste,其中paste deploy是用来发现和配置WSGI应用的一套系统,对于WSGI应用的使用者而言,可以方便地从配置文件汇总加载WSGI应用(loadapp);对于WSGI应用的开发人员而言,只需要给自己的应用提供一套简单的入口点即可。

  PasteDeploy的官方文档在这里,其发布在Pypi上的发行包在这里下载。借助Python的pypi包管理机制,我们可以非常方便地安装PasteDeploy:

# pip install PasteDeploy

  

  下面的词语每组内的等价:

  1. 应用,app,application;

  2. 过滤器,filter;

  3. 管道,pipeline;

  4. 工厂函数,factory;

  5. 组合, composite;

  6. 类型, type;

  7. 段, section

  这些都是PasteDeploy的基本概念,非常容易识别。

  既然PasteDeploy是用来配置和管理WSGI 应用的,不妨首先看一下PasteDeploy配置文件的格式。

  一、PasteDeploy配置文件格式

  

  PasteDeploy配置文件由若干section组成,section的声明格式如下:

  [type:name]

  其中,方括号括起的section声明一个新section的开始,section的声明由两部分组成,section的类型(type)和section的名称(name),如:[app:main]等。section的type可以有:app、composite、filter、pipeline、filter-app等。

  每个section中具体配置项的格式就是基本的ini格式: key = value ,所有从PasteDeploy配置文件中提取的参数键、值都以字符串的形式传入底层实现。

  此外,PasteDeploy的配置文件中使用“#”标注注释。

  在基本了解PasteDeploy配置文件的书写格式后,我们不妨看一个实例,来具体了解不同type的section。

  

  二、PasteDeploy中section的不同type

  

  示例1:PasteDeploy配置文件

  [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   [app:wiki]
  use = call:mywiki.main:application
  database = sqlite:/home/me/wiki.db   [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:main]
  use = egg:MyEgg
  filter-with = printdebug   [filter:printdebug]
  use = egg:Paste#printdebug   [pipeline:main]
  pipeline = filter1 filter2 filter3 app
  ...

  上面的示例文件列出了若干不同type的section示意,下面就一一探讨PasteDeploy可定义的section type.

  

  2.1  Type = composite(组合应用)

  顾名思义,组合应用由若干WSGI应用组成,composite为这些应用提供更高一层的分配工作。

  下面具体分析示例1中的如下部分:

[composite:main]
use = egg:Paste#urlmap
/ = home
/blog = blog
/wiki = wiki
/cms = config:cms.ini

  该段配置文件定义了一个名为main、类型为composite的section,方括号的声明以下是该section的具体配置,遵循 key = value 的统一格式。

  Composite类型的section将URL请求分配给其他的WSGI应用。 use = egg:Paste#urlmap 意味着使用 Paste 包中的 urlmap 应用。urlmap是Paste提供的一套通用的composite应用,作用就是根据用户请求的URL前缀,将用户请求映射到对应的WSGI应用上去。这里的WSGI应用有:"home", "blog", "wiki" 和 "config:cms.ini"。

  最后一项仅仅是参考了同一个目录中的另一个文件"cms.ini"

  

  2.2  Type = app(WSGI应用)

  回到示例1中的下一部分:

[app:home]
use = egg:Paste#static
document_root = %(here)s/htdocs [app:wiki]
use = call:mywiki.main:application
database = sqlite:/home/me/wiki.db

  app类型的section声明一个具体的WSGI应用。调用哪个python module中的app代码则由的use后的值指定。

  这里的 egg:Paste#static 是另一个简单应用,作用仅仅是呈现静态页面。它接收了一个配置项: document_root ,后面的值可以从全局配置[DEFAULT](大小写敏感)中提取,提取方法s是使用变量替换:比如

%(var_name)s 的形式。

  这里 %(here)s 的意思是这个示例配置文件所在的目录,因为相对路径在不同服务器中的解释方法不同,出于移植性的考虑,官方文档上推荐当前这种写法。

  示例中定义了多个app类型的section,因为PasteDeploy的配置文件中允许定义多个app类型的section,同时要求每个WSGI应用也都应该拥有自己的section。这样,每一个WSGI应用在配置文件中都有一个

app类型的section与之对应,默认地,"main"应用对应于 app:main 或 app 。

  应用的具体实现要在section中配置,有两种方法专门用于指出应用对应的代码:使用URI(用use标识)或 直接指向实现代码(用protocol标识)。

  

  2.2.1  使用另一个URI

  采用该方法的特点是指出应用的实现代码的那一条 key = value 配置项采用"use"作为键,该方法也有许多变种,官方的示例中给出了一些介绍:

[app:myapp]
use = config:another_config_file.ini#app_name # 或任意URI:
[app:myotherapp]
use = egg:MyApp # 或指明某个模块中的可调用:
[app:mythirdapp]
use = call:my.project:myapplication # 甚至是其他的section:
[app:mylastapp]
use = myotherapp

  最后指向其他的section的那个例子,看起来似乎没有什么意义,似乎只是两个相同的WSGI应用。但是这样的定义允许我们在 [app:mylastapp] 这个应用中定义一些局部的配置项,从而在重用代码的同时覆写它引用的应用配置。

  2.2.2  直接指向应用的实现代码

  采用该方法的特点是指出实现代码的那一条 key = value 配置项采用“协议”作为键,所谓“协议”即protocol,告诉PasteDeploy即将加载的对象类型,如:

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

  该例的protocol paste.app_factory 是一个应用的工厂函数,指明import对象的类型;值 myapp.modulename:app_factory 指明具体加载的模块和方法。

  关于PasteDeploy的协议,进而可以定义的工厂函数类型,我们在下文对所有section可选的type有一定的了解后再进行探讨。

  

  2.3  Type = filter(过滤器)

  filter是作用于WSGI应用上的函数或方法,以app为唯一的参数,并返回一个“过滤”后的app。归功于WSGI接口的规范,不同的filter可以依次“过滤”某一app,事实上多个filter处理一个app也就是下文中提到的管道(pipeline)。

  在PasteDeploy的配置文件中有多种方法来“过滤”应用,比如示例1中:

[app:main]
use = egg:MyEgg
filter-with = printdebug [filter:printdebug]
use = egg:Paste#printdebug

  在 [app:main] 的 filter-with 字段指明用来处理该应用的filter,就指定了名为"printdebug"的filter来处理应用"main"。在 [filter:printdebug] 中还可以定义新的 filter-with 字段,从而将处理关系延续下去。

  

  2.4  Type = filter-app

  同样是处理应用,在PasteDeploy配置文件中可以有着不同的写法,比如示例1中的下面部分,就是使用filter-app类型的section来声明一个filter:

[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:NAME]类型的section声明了一个filter,指定使用的代码,以及要处理的应用: next 字段的值。从而PasteDeploy会自动地将过滤器"blog"作用在应用"blogapp"上。

  2.5  Type = pipeline

  pipeline便于对一个应用添加多个过滤器,比如示例1中:

[pipeline:main]
pipeline = filter1 filter2 filter3 app

  就指定了在app上施加三个filter进行处理。

  总结起来,想要在某个应用前添加多个filter,共有 [filter-app:...]  [pipeline:...] 和 [app:...] filter-with = ... 等方法。

  三、局部配置与全局配置

  3.1  局部配置与全局配置的格式

  PasteDeploy配置文件的所有配置项均使用 key = value 格式,但是局部配置项和全局配置项定义的位置不同。如:

[app:blog]
use = egg:MyBlog
database = mysql://localhost/blogdb
blogname = This Is My Blog! [app:otherblog]
use = blog
blogname = The other face of my blog

  每一个section内设置具体的键值关系,构成这些section自己的局部配置。

  为了便于不同的应用读取某些固定的系统信息,PasteDeploy允许设置全局配置变量,所有的全局配置必须放在[DEFAULT]字段下设置,如:

[DEFAULT]
admin_email = webmaster@example.com [app:main]
use = ...
set admin_email = bob@example.com

  注意[DEFAULT]段名是大小写敏感的,因此必须严格大写。

  3.2  局部配置和全局配置的覆写

  3.1中的两个例子,实际上展示了局部配置和全局配置的覆写,这里详细介绍,首先看局部配置的覆写:

[app:blog]
use = egg:MyBlog
database = mysql://localhost/blogdb
blogname = This Is My Blog! [app:otherblog]
use = blog
blogname = The other face of my blog

  从2.2.1中已经知道,一些section可以直接复用其他section的代码,并定制配置信息,这里 [app:otherblog] 就采用了 [app:blog] 的代码,同时将配置项 blogname 改为自己特定的。

  另一方面,应用在本地可以修改全局配置项的值:

[DEFAULT]
admin_email = webmaster@example.com

[app:main]
use = ...
set admin_email = bob@example.com

  只需要在要覆写的键前加 set 即可。

  

  至于为什么要探讨局部配置与全局配置,是因为二者在传递给不同类型的factory function时对应的参数不同,这些将在下文详细探讨。

  四、实现factory函数

  本文的第二部分探讨了PasteDeploy中的若干种“协议”,事实上对应了实现时的不同类型,包括 paste.app_factory  paste.composite_factory  paste.filter_factory  paste.server_factory 等。这些“协议”的 value 都必须是一个可调用(函数、方法、类、可调用对象等)。

  这些“协议”封装WSGI应用,使其成为app、composite、filter等类型的组件,这些factory对应的格式有

  4.1  paste.app_factory

  这是最常见的factory,接收配置参数,用来返回一个WSGI应用,第三部分中介绍的全局配置以字典的形式传入,局部配置则以关键字参数(keyword arguments)的形式传入。

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

  4.2  paste.composite_factory

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

  是不是与 app_factory 非常相似,composite的factory函数就是在app factory的基础上增加了 loader 参数,该参数有一些方法,比如 get_app(name_or_uri, global_conf=None) 返回指定名称的WSGI应用, get_filter 、 get_server 也有着类似的作用。

  下面是官方给出的一个composite_factory的示例:

def pipeline_factory(loader, global_config, pipeline):
# space-separated list of filter and app names:
pipeline = pipeline.split()
filters = [loader.get_filter(n) for n in pipeline[:-1]]
app = loader.get_app(pipeline[-1])
filters.reverse() # apply in reverse order!
for filter in filters:
app = filter(app)
return app

  事实上,这也是一个pipeline factory,这个例子需要搭配PasteDeploy配置文件的具体配置工作,其中的filter、app等也都需要额外实现:

[composite:main]
use = <pipeline_factory_uri>
pipeline = egg:Paste#printdebug session myapp [filter:session]
use = egg:Paste#session
store = memory [app:myapp]
use = egg:MyApp

  这个factory将PasteDeploy配置文件中某个pipeline section中的filter与app分离,将位于管道末端的app(myapp)作为参数依次传递给filter(printdebug, session),由于filter一旦处理成功也返回一个app,否则拦截用户请求,所以这个过程可以一直持续下去,直至所有的filter对app进行完处理。

  4.3  paste.filter_factory

  filter factory与app factory非常相似,只是返回filter而不是WSGI app。filter必须是可调用的,接收WSGI app为唯一的参数,返回处理过的该app。paste deploy官方也给出了一个这样的例子:

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']

  该filter factory产生一个简单的认证过滤器,过滤器工厂函数接收配置参数,进行处理后和app一起传给真正实现过滤器功能的类 AuthFilter 。

   auth_filter_factory 中的 filter 方法就是封装了具体实现的过滤器,它只接收WSGI app作为自己的参数,具体的配置参数和认证逻辑则由 class AuthFilter 的实例完成。

   class AuthFilter 的实例是一个可调用对象,事实上其 __call__ 方法就是实现了一个符合WSGI 规范的app。WSGI app以CGI形式的环境变量environ和回调函数为参数。本例的逻辑很简单:如果在server发来的环境信息中包含了外部认证时设置的"REMOTE_USER",则直接返回传进来的app,否则拒绝用户的认证请求。

  WSGI app通过 return 语句返回HTTP Response body,由参数中的回调函数返回HTTP 响应状态码和HTTP Response header,这都属于WSGI的规范,这里不做深入探讨。

  4.4  paste.filter_app_factory

  与filter_factory 非常相似,只是接收和返回的均为WSGI app,没有filter。

  4.3示例中如果进行如下修改:

class AuthFilter(object):
def __init__(self, app, global_conf, req_usernames):
....

  那么 class AuthFilter 就是一个filter_app_factory, 对比4.1的 paste.app_factory 和4.3的 paste.filter_app_factory 即可理解。

  4.5  paste.server_factory

  返回WSGI server。

  WSGI server接收唯一的参数——WSGI app,并为其服务。一个简单的 paste.server_factory 例子如下:

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

  该工厂函数同样封装了配置参数等信息,返回一个只接收WSGI app做参数的可调用,至于  class Server 就留待具体实现。

  4.6  paste.server_runner

  与paste.server_factory 类似,只是WSGI app应该以第一参数传入,同时返回的server要立即运行。

  总结

  本文是学习PasteDeploy时的笔记,资料文档的示例非常丰富通俗,就是逻辑比较凌乱,读起来总觉的别扭。经过整理,看起来觉得思路清晰多了。结合WSGI规范,对Python下网络开发又有了进一步的理解。

2014.12.17 补充:

paste.deploy.wsgi

paste.deploy.loadwsgi.loadapp(uri, name=None, **kw) 
  
  
paste.deploy.loadwsgi.loadserver(uri, name=None, **kw) 
  
  
paste.deploy.loadwsgi.loadfilter(uri, name=None, **kw) 
  
  
paste.deploy.loadwsgi.appconfig(uri, name=None, relative_to=None, global_conf=None) 
  这个项目的文档真是不怎样,loadapp 到底怎么用,这里说是在paste.deploy的wsgi模块下,在实际项目和文档的其他位置中直接位于 paste.deploy 下的。这里直接扔了四个函数不给任何说明,服了服了。

详解Paste deploy的更多相关文章

  1. Openstack Paste.ini 文件详解

    目录 目录 pasteini 配置文件详解 composite pipeline filter app DEFAULT server Request 被 pasteini 处理的流程 如何加载 pas ...

  2. OpenStack Paste.ini详解(二)

    接着OpenStack Paste.ini详解(一),接下来就分析request被paste.ini处理的流程 WSGI server接收到URL形式的request时,这些request首先会被Pa ...

  3. (转)linux paste命令用法详解

    linux paste命令用法详解原文:http://www.xfcodes.com/linuxcmd/mulu/10211.htmlinux下paste命令,可用于合并文件的列. 功能说明:合并文件 ...

  4. 从苦逼到牛逼,详解Linux运维工程师的打怪升级之路

    做运维也快四年多了,就像游戏打怪升级,升级后知识体系和运维体系也相对变化挺大,学习了很多新的知识点. 运维工程师是从一个呆逼进化为苦逼再成长为牛逼的过程,前提在于你要能忍能干能拼,还要具有敏锐的嗅觉感 ...

  5. 详解Linux运维工程师

    运维工程师是从一个呆逼进化为苦逼再成长为牛逼的过程,前提在于你要能忍能干能拼,还要具有敏锐的嗅觉感知前方潮流变化.如:今年大数据,人工智能比较火……(相对表示就是 Python 比较火) 之前写过运维 ...

  6. 史上最全的maven的pom.xml文件详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  7. redis配置详解

    ##redis配置详解 # Redis configuration file example. # # Note that in order to read the configuration fil ...

  8. sort详解2

    linux sort 命令详解 sort是在Linux里非常常用的一个命令,管排序的,集中精力,五分钟搞定sort,现在开始! 1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比 ...

  9. Maven-pom.xml详解

    (看的比较累,可以直接看最后面有针对整个pom.xml的注解) pom的作用 pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵 ...

随机推荐

  1. 多媒体文件格式解析之MP3

    音频文件格式MP3 1. MP3是什么? MP3是MPEG-1 Audio Layer 3的缩写,是当今较流行的一种数字音频编码和有损压缩格式,它设计用来大幅度地降低音频数据量,而对于大多数用户的听觉 ...

  2. Lintcode: Majority Number 解题报告

    Majority Number 原题链接:http://lintcode.com/en/problem/majority-number/# Given an array of integers, th ...

  3. python keras 神经网络框架 的使用以及实例

    先吐槽一下这个基于theano的keras有多难装,反正我是在windows下折腾到不行(需要64bit,vs c++2015),所以自己装了一个双系统.这才感到linux系统的强大之初,难怪大公司都 ...

  4. 算法篇---java算法应用

    算法应用之百钱买白鸡 案列说明:主要内容是:公鸡5元一只,母鸡3元一只,小鸡1元三只,问100元怎样可以买100鸡? 思想:想要实现此算法,只要明白各种条件的关系即可,而且知道公鸡最多买20只,母鸡最 ...

  5. linux 删除文件,df空间不变化

    今天遇到一个问题,就是linux服务器空间满了,可是删除了软件后. 查看空间,没有变化 ???啥情况 那么去查看删除的情况吧. [root@VM_0_4_centos usr]# lsof|grep ...

  6. [转]Oracle trunc()函数的用法

    原文地址:http://www.cnblogs.com/gengaixue/archive/2012/11/21/2781037.html 1.TRUNC(for dates) TRUNC函数为指定元 ...

  7. 如何让docker以daemon方式运行/bin/bash

    本文转自:https://segmentfault.com/q/1010000000424935 问题: 我想在docker run的时候,用-d参数运行/bin/bash,然后让这个bash一直跑着 ...

  8. 俞军的PM12条

     俞军的PM12条:1.PM首先是用户2.站在用户角度看待问题3.用户体验是一个完整的过程4.追求效果,不做没用的东西5.发现需求,而不是创造需求6.决定不做什么,往往比决定做什么更重要7.用户是很难 ...

  9. webstorm 设置jsp支持ZenCoding

    setting -> File Type - html 里面增加*.jsp

  10. FileChannel类的理解和使用

    FileChannel类的理解和使用(java.nio.channels.FileChannel) 知识点: 1.FileChannel类及方法理解:2.普通输入输出流复制文件:3.FileChann ...