- 论坛徽章:
- 0
|
第六章标准处理器
6.1发布处理器
发布处理器是一种快速开发应用程序,避免(avoid)直接书写处理器的好方法。收到Zope中ZPublisher的启发。
6.1.1简介
使用处理器需要书写如下配置:
<Directory /some/path>
SetHandler mod_python
PythonHandler mod_python.publisher
</Directory>
这个处理器允许通过URL在模块中存储函数和变量。例如,如果有如下模块,叫做'hello.py':
""" Publisher example """
def say(req,what="NOTHING"):
return "I am saying %s" % what
则如下路径显示"I am saying NOTHING"
http://www.mysite.com/hello.py/say
如下路径显示"I am saying hello"
http://www.mysite.com/hello.py/say?what=hello
6.1.2发布处理器规则(algorithm)
发布处理器从URI映射到Python变量或可执行对象,返回调用的返回值。
Traversal(?)
发布处理器定位和导入URI指定的模块。模块的位置按照req.filename属性指定。在到如之前,如果有扩展名则丢弃。
如果req.filename为空,则模块名缺省为index。
一旦模块成功导入,则URI剩余的部分成为query字段的开始(a.k.a also known as也叫做PATH_INFO),来在模块里查找对象。发布处理器切断路径,从左到右,每个元素一次的映射到Python对象。
如果URL里未指定path_info,则发布处理器使用缺省的'index'。如果最后一个元素是模块里的一个对象,且它领先与一个目录(也就是没有给出模块名),模块名也会默认到'index'。
当如下情况发生时,转换结束,并返回HTTP_NOT_FOUND到客户端:
任何一个横断(traverse?)对象名以下划线开头。使用下划线保护对象不被web存取。
模块冲突(encounter),发布的对象因为安全原因不可以成为模块。
如果路径中找不到对象,则HTTP_NOT_FOUND也会发送到客户端。
例如,如下的配置:
DocumentRoot /some/dir
<Directory /some/dir>
SetHandler mod_python
PythonHandler mod_python.publisher
</Directory>
如下是脚本'/some/dir/index.py':
def index(req):
return "We are in index()"
def hello(req):
return "We are in hello()"
然后:
http://www.mysite.com/index/index 显示"We are in index()"
http://www.mysite.com/index/ 显示"We are in index()"
http://www.mysite.com/index/hello 显示"We are in hello()"
http://www.mysite.com/hello 显示"We are in hello()"
http://www.mysite.com/spam 显示'404 Not Found'
如果找到了目标对象,且它是可调用对象而不是一个类,则发布处理器会提取一个对象预期的列表。这个列表包含从HTML表单提交数据中的字段。字段值和字段名以字符串匹配并传入可调用对象的参数。任何没有匹配的名字都被默认丢弃,除非目标对象有一个**kwargs风格的参数。未匹配参数传入这个词典中。
如果目标对象不是可调用的或者是一个类,则会返回它创建的字符串到客户端。
发布处理器提供了对模块和函数简单的存取控制。
在每个处理阶段,发布处理器按顺序检查__auth__和__access__属性,还有__auth_realm__属性。
如果__auth__是可调用的,将会被传入三个参数:一个请求对象,字符串包含用户名和密码。如果返回值是False,则将发送HTTP_UNAUTHORIZED到客户端,一般来说还会弹出一个输入密码的对话框。
如果__auth__是一个词典,则用户名和密码按照键值对在词典中尝试匹配。如果不匹配则返回HTTP_UNAUTHORIZED。注意,如果明文将密码存入源代码中是不安全的。
__auth__也可以是常量。在这种情况下,如果为False(也同None、0、""、等等)则返回HTTP_UNAUTHORIZED。
如果存在__auth_realm__字符串,它将会被发送到客户端作为认证区域的提示,通常还显示在密码提示框中。
如果__access__存在并可调用,则传入两个参数:请求对象和用户名字符串。如果返回值为False则发送HTTP_FORBIDDEN到客户端。
如果__access__是一个列表,则用户名将会被尝试匹配。如果用户名不再列表中,则返回HTTP_FORBIDDEN。
类似的__auth__、__access__也可以是常量。
在下例中,仅用户'eggs'使用密码'spam'可以访问函数hello:
__auth_realm__="Members only"
def __auth__(req,user,passwd):
if user=="eggs" and passwd=="spam":
return 1
else:
return 0
def __access__(req,user):
if user=="eggs":
return 1
else:
return 0
def hello(req):
return "hello"
这里还有一个具有相同功能,但使用类似技术:
__auth__realm__="Members only"
__auth__={"eggs":"spam"}
__access__=["eggs"]
def hello(req):
return "hello"
如果函数无法被指定属性,为了保护函数,也可以将__auth__和__access__函数放入这个函数中定义,如:
def sensitive(req): #受保护函数
def __auth__(req,user,password):
if user=="spam" and password=="eggs":
return 1
else:
return 0
#受保护函数的函数体
return 'sensitive information'
注意,这种技术也可用于__auth__或__access__是常量的情况,但是不可以是词典或列表。
__auth__和__access__机制独立于PythonAuthenHandler而存在。它可能使用,例如认证处理器。然后__access__列表用于已经验证过的用户访问具体函数。
注意:为了让mod_python可以访问__auth__,包含它的模块必须首先导入。因此,任何模块级(module-level)的代码在导入__auth__之前,即时__auth__为False,也是可以执行的。为了真正的保护模块,使用另外一种认证技术,比如apache的mod_auth模块或者用mod_python的PythonAuthenHandler处理器。
6.1.3表单数据
在处理参数结束后,发布处理器将会创建一个FieldStorage类的实例。实例的引用存入请求对象的form属性中。
每次请求只能拥有一个FieldStorage类的实例,在使用发布处理器的时候不可以自己实例化FieldStorage,只能使用Request.form代替。
6.2PSP处理器
PSP处理器是处理含有mod_python.psp模块中psp类的。要使用它,只需简单的在httpd的配置中加入:
AddHandler mod_python .psp
PythonHandler mod_python.psp
更多的PSP语法参见4.9节。
如果打开了服务器选项PythonDebug为On,则在URL的末尾添加下划线"_"会显示响应的PSP源代码和对应的Python代码。这对调试是非常有用的。
注意:开启调试选项时,远程用户同样有权查看PSP源码。
6.3CGI处理器
CGI处理器用来在mod_python中模拟CGI环境。
但是注意,在Python级别并不能真正的模拟出一个完整的CGI环境。stdin和stdout是由sys.stdin和sys.stdout来替换(substitute)的。环境变量也被替换为词典。一点类似(implication)是外部程序通过环境变量os.system交互,等。不要指望外部可以看到Python的环境变量,也不要指望读写标准输入输出象真正的CGI环境那样。
这个处理器是为了逐步(step stone)移植(migration)CGI遗留(legacy)下来的代码。不建议大量使用这种方式。因为CGI程序没有打算(intend)过在线程环境中使用(比如请求更换当前目录,就不是线程安全的。这就需要在多线程服务器程序中使用线程锁)。他的实现方式也远不如mod_python中的其他方式。
需要使用它,只需在.htaccess文件中加入如下内容:
SetHandler mod_python
PythonHandler mod_python.cgihandler
在版本2.7中,cgihandler会完全的重新载入来间接(indirectly)的重新导入模块。这是为了保护装入模块列表(sys.modules)来优先(prior)执行CGI脚本,然后在脚本执行后对比导入模块。除了一些__file__属性指向标准Python库的模块外,将会被在sys.modules中删除来强制Python在下次CGI脚本导入时再次装入他们。
如果你不希望如上的行为,可以编辑'cgihandler.py'文件注释掉###代码。
测试表明,cgihandler在多次文件上传时会发生内存泄漏(leak)。而且至今还没有完全解决这个问题。暂时的解决办法是设置apache的MaxRequestsPerChild到一个非零的值。
完成...
注:本文由gashero翻译,欢迎转载,转载前情确保同意英文原版的版权声明。因本人英语水平有限,文中有错误之处欢迎指出,意见发送到harry.python@gmail.com。本文不定期更新,请关注"河边的小屋"(http://blog.csdn.net/gashero)来查看最新翻译版本。翻译全程特别感谢"画鬓如霜"的支持,没有你的爱我无法完成这一切。也感谢python-chinese邮件列表上朋友的支持。 |
|