|
中华网络安全联盟 作者:未知 来源:转载 时间:2006-4-12
第三章指南
3.1使用发布器(Publisher)的快速例子
这一节提供无需太多细节的发布器指南。更多如何使用mod_python处理器的细节将在以后解释。
发布器(publisher)提供了发布mod_python标准模块的方式。需要在配置文件中加入如下配置:
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
下例会返回简单的表单数据。询问姓名、电子邮件、注释之后将会给管理员发邮件。这个简单的应用程序由两个文件组成:form.html用于提交数据,form.py用于处理表单动作。
如下是表单:
<html>
Please provide feedback below:
<p>
<form action="form.py/email" method="POST">
Name: <input type="text" name="name"><br>
Email: <input type="text" name="email"><br>
Comment: <textarea name="comment" rows=4 cols=20></textarea><br>
<input type="submit">
</form>
</html>
注意表单的action属性指向form.py/email调用,如下创建form.py,如下:
import smtplib
WEBMASTER="webmaster" #管理员电邮
SMTP_SERVER="localhost" #本机SMTP服务器
def email(req,name,email,comment):
#一定要确保用户提供了所有的参数
if not(name and email and comment):
return "缺少必要的参数"
#创建消息文本
msg=""" \
From: %s
Subject: feedback
To: %s
I have the following comment:
%s
Thank You,
%s
""" % (email,WEBMASTER,comment,name)
#发送信息
conn=smtplib.SMTP(SMTP_SERVER)
conn.sendmail(email,[WEBMASTER],msg)
conn.quit()
#提供返回页面
s="""\
<html>
Dear %s,<br>
Thank you for your kind comments, we
will get back to you shortly.
</html>""" % name
return name
当用户点击提交按钮时,发布器将会装入email函数到form模块,传递表单字段作为关键字参数。也会传递请求对象到req。
注意逆必须要有req参数。发布器已经可以很聪明的传递必要的参数。函数的返回值将被发送到客户端浏览器。
即使使用发布器可以非常简单的处理,但是程序仍然可以利用mod_python的强大功能,比如调用请求对象。当然也可以调用本地的mod_python处理器来完成大量的工作。比如设置HTML头路由req.headers_out;返回错误抛出apache.SERVER_ERROR异常;从客户端的重定向读写文件req.write()和req.read(),等等。
阅读6.1节了解更多关于发布器的详细信息。
3.2apache处理器概览
节标题翻译有误,应为"快速学习apache如何处理请求"。
如果你想要深入钻研mod_python的功能,需要理解什么是处理器。
apache分阶段(phase)处理请求。比如第一个阶段是用户认证,之后是检验用户是否有权访问特定的文件,然后是读取文件并发送到客户端。一个典型的静态文件请求包含三个阶段:1.翻译URI到文件位置2.读取文件并发送到客户端3.记录请求日志。更复杂的处理依赖于配置文件。
一个处理器就是初始处理某个阶段的函数。同一个阶段可以有多于一个处理器进行处理,被叫做apache序列。对应每个阶段有个缺省的apache处理器(大多数只做缺省动作或者什么都不作)。然后由其他的apache模块提供处理器,比如mod_python。
mod_python提供了apache每一个重要的处理器。mod_python处理器缺省时不会做任何事情,除非用特定的配置文件标志。这些标志以"Python"开始并以"Handler"结尾(如:PythonAuthenHandler),指定Python函数来处理指定的阶段。所以mod_python的主函数只是作为发报机的角色连接apache处理器和Python函数。
最常用的处理器是PythonHandler。它处理含有上下文的请求。因为它没有名字,所以有时也成为通用处理器。这个处理器的apache缺省行为是读取文件并发送到客户端。大多数应用应该重写这个处理器。
3.3mod_python做了什么
我们假设有如下配置:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonDebug On
</Directory>
所以还需要一个如下文件,'/mywebdir/myscript.py'如下:
from mod_python import apache
def handler(req):
req.content_type="text/plain"
req.write("Hello World!")
return apache.OK
如下的事情将会发生:AddHandler标志告诉apache所有的以.py结尾的'/mywebdir'下或其子目录下的文件请求都由mod_python负责处理。'PythonHandler myscript'标志告诉mod_python通用处理器在myscript脚本。'PythonDebug On'标志告诉mod_python如果发生错误,则把错误信息输出到客户端,便于开发。
当请求到来时,apache开始分步骤处理请求并讲请求发送到mod_python。mod_python处理器检查配置获取处理器。在本例,我们除了通用处理器之外没有调用其他东西。当读取配置到'PythonHandler myscript'时,会发生下面的事情:
1.如果没有做过,假设预设目录已经存在于sys.path中。
2.尝试按名字导入模块myscript。注意子目录是不在sys.path中的,如果需要只能按照包名的方式调用。
3.在myscript中查找函数handler
4.调用这个函数并传递请求对象(关于请求对象的更多东西在后面)
5.在这里我们细致研究一下脚本:
from mod_python import apache
导入apache模块来获取apache的接口。大多数mod_python程序需要有这一行。
def handler(req):
这是处理器函数的声明。叫做'handler'是因为mod_python按照配置标志寻找函数。将配置标志转换成小写,然后去掉'python'即可。这样'PythonHandler'就成了'handler'。当然也可以用其他的名字,但是需要用'::'来分隔函数名,比如一个处理器函数叫'spam',那么配置标志就是'PythonHandler myscript::spam'
注意,处理器必须包含一个请求对象参数。请求对象提供了关于请求的大量信息,比如客户端的IP,请求头,URL等。向客户端发送信息也需要用到请求对象,这里是没有'response'对象的。
req.content_type="text/plain"
设置文档MIME类型为'text/plain'。缺省的是'text/html',但是如果处理器没有打算返回html,那么'text/plain'更恰当(appropriate)一些。特别注意:需要在req.write方法之前调用如上语句,因为一旦调用req.write,HTTP响应头就被发送出去了,其后的HTTP响应头的改变都会忽略。
req.write("Hello World!")
将会把字符串写入到客户端。
return apache.OK
告知apache,请求处理完成并成功。如果没有返回OK,则apache会自动返回为apache.HTTP_INTERNAL_SERVER_ERROR或return apache.HTTP_FORBIDDEN。当处理失败时会在错误日志中记录,并告知客户端一点错误信息。
小技巧:如果你注意到,会发现如果请求的URL不是指向myscript.py,而只是一个.py结尾的文件,哪怕是一个不存在的文件,也可以得到相同的结果。因为服务器只是将特定结尾的处理直接交给相关模块的,而并不要求那一定是一个存在的文件。
3.4更复杂的例子-认证
现在,你知道写一个处理器多么的简单,下面我们来显示一个更复杂的例子。
如果需要用密码来保护一个目录。比如登录名为'spam',密码为'eggs'。
首先需要告诉apache在需要认证时调用我们的认证处理器。加入PythonAuthenHandler标志到配置文件:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
</Directory>
因为一个模块可以包含多个函数,所以也可以在一个模块中使用多个处理器。
然后是告知apache,使用Basic HTTP认证。仅限有效用户进入。配置如下:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
AuthType Basic
AuthName "Restricted Area"
require valid-user
</Directory>
然后在myscript.py中写认证函数,一个简单认证函数如下:
from mod_python import apache
def authenhandler(req):
pw=req.get_basic_auth_pw()
user=req.user
if user=="spam" and pw=="eggs":
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
如下是逐行解释:
def authenhandler(req):
认证函数的声明,至于为什么叫这个名字,自己可以参考命名规则。
pw=req.get_basic_auth_pw()
这里获取密码。basic HTTP认证采用base64编码发送到服务器。这个函数返回的直接就是密码了。注意必须在获取用户名之前先获取密码。
user=req.user
获取用户名
if user=="spam" and pw=="eggs":
return apache.OK
对比用户名和密码的值,如果正确返回告知验证成功,并进入下一个阶段的处理。在本例里下一个阶段是handler()。
else:
return apache.HTTP_UNAUTHORIZED
告知apache验证失败。这通常会导致客户端浏览器弹出对话框要求用户名和密码。
实测:
发现我使用的httpd-2.0.55提示验证类型无效,一共两种验证类型,一种是Basic一种是Digest,都是不允许的。就是按照如上例子。
终于实验成功了,最上面的配置必须写在httpd.conf中才会有效,写在.htaccess中无效。无论是否指定了AllowOverride FileInfo都是。这样进入一个目录之后会弹出系统的对话框提示输入用户名密码。验证成功后只要浏览器不关闭就可以继续进入这个目录,但是关闭后就需要再次验证。
3.5你自己的404处理器
在某些时候,如果希望返回404(HTTP_NOT_FOUND)或者其他非200的结果到客户端,这里有个窍门。如果从你的处理器返回HTTP_NOT_FOUND, apache将会生成错误页。但是却未必是你喜欢的错误页。
这时,你只要设置req.status=apache.HTTP_NOT_FOUND,提交你的页面,然后返回apache.OK就可以了:
from mod_python import apache
def handler(req):
if req.filename[-17:]=='apache-error.html':
#放行apache的错误页
if req.filename[-18:]=='handler-error.html':
#使用自己的错误页
req.status=apache.HTTP_NOT_FOUND
pagebuffer='页面不存在'
else:
#使用文件内容
pagebuffer=open(req.filename,'r').read()
#输出错误页
req.write(pagebuffer)
return(apache.OK)
完成...
上一页 [1] [2] [3] [4] [5] [6] [7] [8] 下一页 |