简介
安装
配置Apache
写个简单的handler
指南
快速开始,学习发布处理器(Publisher Handler)
快速学习,看一下apache怎样处理请求
那么mod_python到底做了些什么呢?
现在学习一些更复杂的—认证
发布处理器 — publisher
配置apache使用publisher
写脚本
参考
中文文档

简介

mod_python是apache组织的一个项目,通过它,可以开发psp或cgi,mod_python功 能强大,速度快,是非常优秀的web开发工具。一个最主要优点就是在性能上超越传 统CGI。

Apache分阶段的处理请求(比方说:读取请求,解析header, 检查存取路径,等等)。 这些阶段能被称为"处理器"(handler)的函数实现。传统上, "处理器"是由C语言编 写,并编译成Apache的模块。mod_python提供了一个通过Python写的Apache处理器 的来扩展Apache功能的方法。

Mod_python起源于一个被称为Httpdapy(1997)的项目。很长时间以来, Httpdapy并 没有被称作mod_python,因为Httpdapy不是专门用于Apache的。 Httpdapy被设计成 跨平台的,实际上最初是为Netscape server写的(那个时候被称为Nsapy)(1997)

安装

安装略过,通常的系统我们可以直接取得安装包。或者从源码安装也是很简单的。

有两种方法将模块编译并连接到Apache — 静态的,或者作为DSO(Dynamic Shared Object).

DSO是mod_python现在更流行的并且被推荐的方法。模块被编译为一个共享库,在运 行时有服务器动态装入。DSO的好处是模块安装时不需要重新编译Apache,并且需要 时再使用。现在mod_python只支持DSO。

静态连接是一种较老的方法。随着动态连接在大多数的平台上的实现,它被越来越 少的用到。它主要的缺点是需要重新编译Apache,在很多情况下这可不是一个好的 选择。

配置Apache

如果你将mod_python编译成DSO,那么你需要通过在Apache的配置文件(通常称为 httpd.conf 或者 apache.conf)里面加入如下一行,来载入模块。实际路径通常不 一样,例如,我在fedora10上使用yum安装mod_python包,包提供一个配置文 件:/etc/httpd/conf.d/python.conf

LoadModule python_module modules/mod_python.so

以下都以我的fedora10实验机器为例:

在/etc/httpd/conf.d/python.conf(或者其他的apache配置文件都可以)添加:

<Directory "/var/www/html">
        AddHandler mod_python .py
        PythonHandler mptest
        PythonDebug On
</Directory>

addHandler 指示告诉 apache, 所有在mywebdir目录或者是它的子目录下的所有.py文 件,有关于这些文件的任何请求都用mod_python 来处理,(现在多用 "SetHandler mod_python") 。pythonHandler myscript 指示告诉 mod_python 用 myscript 执 行默认的处理器. “pythonDebug On” 指示告诉mod_python如果发生错误,就把错误 信息打印到客户端 (相对于写入日志文件),在开发的时候这个选项非常有用。

现在我们只要在 /var/www/html 目录下放一个 mptest.py 的脚本,就可以访问了。 这个脚本的基本写法如下:

写个简单的handler

将下列代码保存为 /var/www/html/mptest.py 文件:

    1: from mod_python import apache
    2: 
    3: def handler(req):
    4:     req.content_type="text/plain"
    5:     req.write("Hello World!")
    6:     return apache.OK
    7: 

在浏览器输入: http://localhost/mptest.py

现在浏览器应该显示 "Hello World!",如果没有,细心检查步骤。可以使用 httpd -X 在命令行启动apache,这样可以看到apache的一些输出信息,便于出错。

重要的是定义一个 handler 方法,如果我们不是使用 PythonHandler mptest (使 用我们自己的handler:mptest),而是使用 PythonHandler mod_python.publisher (使用mod_python自带的publisher),那么我们的 hander 脚本里面就要有一个 index 方法。

上面的代码里面,如果有utf-8字符集,就在代码最前面(如果你的代码第一行 是'#!/usr/bin/python',那么就在第二行添加)加上:

# -*- coding: utf-8 -*-

至于python文件编码设定,有很多形式(我的python2.5测试),重要在编码设定行包 括下面字符就行:

 #coding:utf8 

最后需要返回 apache.OK (所以需要import apache),不返回这个值,apache会 认为执行出错。

指南

我们已经学会并安装好mod_python,现在可以通过快速阅读本章进入程序开发阶段。

快速开始,学习发布处理器(Publisher Handler)

这一节为我们提供了一个快速的关于发布处理器的概况,从而使我们可以不用关注 太多的细节就可以写出程序。

发布处理器是mod_python的众多标准处理器中的一个,为了使你的发布处理器能够正 常工作,需要在你的配置文件(通常是httpd.conf)中加入下面几句话:

<Directory /var/www/html>
        AddHandler mod_python .py
        PythonHandler mod_python.publisher
        PythonDebug On
</Directory>

接下来的这个例子展示了一个简单的返回表单,这个表单询问用户的名称,电子邮 箱,地址和意见,然后发送一封电子邮件给网络管理员,信的内容就是用户填写的 意见。这个简单的程序包括两个文件:form.html—用来收集数据,form.py—表 单的action指令发送的目标。

form.html代码 :

    1: <html>
    2:    请填写下面的回馈表单:
    3:     <form action="form.py/email" method="POST">
    4:           用户名:     <input type="text" name="name"><br>
    5:           电子邮件:    <input type="text" name="email"><br>
    6:           意见:  <textarea name="comment" rows=4 cols=20></textarea><br>
    7:                     <input type="submit">
    8:     </form>
    9: </html>
   10: 

注意<form>标签的action指向form.py/email。接下来我们编写这个名叫form.py的 脚本,如下:

    1: # -*- coding: utf-8 -*-
    2: import smtplib
    3: WEBMASTER = "webmaster" # webmaster e-mail
    4: SMTP_SERVER = "localhost" # your SMTP server
    5: def email(req, name, email, comment):
    6:     #确定用户提供了所有的参数
    7:     if not (name and email and comment):
    8:         return "A required parameter is missing, \
    9:             please go back and correct the error"
   10:              # 创建消息对话框
   11:     msg = """\
   12:           From: %s
   13:           Subject: feedback
   14:           To: %s
   15:           I have the following comment:
   16:           %s
   17:              Thank You,
   18:           %s
   19: """ % (email, WEBMASTER, comment, name)
   20: #发出信件
   21: #conn = smtplib.SMTP(SMTP_SERVER)
   22: #conn.sendmail(email, [WEBMASTER], msg)
   23: #conn.quit()
   24: # 返回用户信息
   25:     s = """\
   26: <html>
   27:       亲爱的%s,<br>
   28:       谢谢你的意见,我们会在近期与你联系.
   29: </html>""" % name
   30:     return s
   31: 

为了保证实例的简单,我把作者的发信功能注释了。你如果很明白SMTP可以试试。

将上面的form.html和form.py都放到/var/www/html目录中,用浏览器访问测试。

当用户点击确定按钮的时候,发布处理器就会调用form模块中的email方法,把表单 中各个域的值做为email方法的参数传递给email方法,并且也会把request的对象 req一并传递过去。

并不是非要把req做为email方法的一个参数不可,如果你不需要它,可以省略掉。 发布处理器很灵活,它只会把那些在方法的参数列表中存在参数所相对应的域的值 传递过去。

方法的返回值在浏览器中显示出来。

虽然发布处理器极大的简化了mod_python编程,但是mod_python所具有的强大功能 却没有损失,因为发布处理器可以访问到request对象,所以你可以做到与原生 (native)mod_python处理器完全相同的事情。 举例来说:

通过req.headers可以自定义头(header),通过抛出apache.SERVERERROR返回异常, 通过req.write()和req.read()直接读写客户端等等。

快速学习,看一下apache怎样处理请求

如果你想更深入的研究mod_python的功能,你需要弄明白一个处理器到底是什么。

apache是分步骤处理请求的,例如,第一步可能是确定用户,接下来验证用户是不是允许访问特定的文件,然后读这个文件并把它发送到客户端。一个典型的静态文件请求包括三步:(1)解析请求的URI为文件在服务器上的路径。(2)读文件并把它发送到客户端。(3)记录请求日志。这个日志中记录了执行的步骤,记录内容的多少取决于配置文件中的设置。

一个处理器就是处理其中某一步的方法,有可能在处理某一步的时候需要用到不止一个处理器,在这种情况下,这几个处理器将被apache依次调用。每一步都会有一个默认的apache动作(大多数情况下都是很基础的方法或者不做任何事情)。与此同时,apache模块还提供了附加的处理器,比如 mod_python.

mod_python为apache提供了几乎所有需要用到的处理器,mod_python的处理器默认的不会提供任何方法,除非我们明确的在配置文件中指示。这些指示以"python"开始,以"Handler"结束(比如: pythonAuthenHandler )它对应于一个python方法,这个方法处理众多步骤中的一步。所以mod_python的方法扮演的是发报机(dispatcher)的角色,通过它联系apache动作和开发人员(比如你)写的python方法。

最经常用到的处理器是 pythonHandler,它处理那些请求提供内容的步骤。因为它没有名字,所以有时候它被作为泛指的处理器。这个处理器的默认的apache动作是读文件并把它发送的客户端。你写的大多数程序都会重载这个处理器。

那么mod_python到底做了些什么呢?

假设我们有下面的配置文件:

    <Directory /mywebdir>
       AddHandler mod_python .py
       PythonHandler myscript
       PythonDebug On
    </Directory>

注意: /mywebdir 是一个物理绝对路径。 还有一个python程序 ‘/mywedir/myscript.py’如下:

    1: from mod_python import apache
    2: def handler(req):
    3:    req.content_type = "text/plain"
    4:    req.write("Hello World!")
    5:    return apache.OK
    6: 

解释一下这个程序:

addHandler 指示告诉 apache, 所有在mywebdir目录或者是它的子目录下的所有.py文 件,有关于这些文件的任何请求都用mod_python 来处理, pythonHandler myscript 指示告诉 mod_python 用 myscript 执行默认的处理器. “pythonDebug On” 指示告 诉mod_python如果发生错误,就把错误信息打印到客户端 (相对于写入日志文件), 在开发的时候这个选项非常有用。

当一个请求发出时,apache通过调用mod_python中的处理器分步处理请 求,Mod_python首先检查请求的那个处理器是否在配置文件中指定了(记住,它的角 色是发报机dispatcher),在我们的例子中,mod_python除了调用默认的那个处理器外 不会调用其他的任何处理器,然后,mod_python会发现"pythonHandler myscript"指 示,并按照下面的步骤来进行:

1.如果以前没有做过,那么就把pythonHandler指定的那个目录加到sys.path中。

2.尝试引入myscript的模块(注意,如果myscript在pythonHandler指定那个目录的 子目录中的话,引入会出错,因为子目录并没有加到sys.path中,解决这种情况的 方法是使用包)例如:”pythonHandler subdir.myscript”

3.在myscript中寻找名字叫handler的方法。

4.调用这个方法,并把request对象传递给它。

5.现在让我们深入这段脚本看一下:

from mod_python import apache

这个引入语句提供给我们一个访问apache的接口。除了极少数情况外,每一个 mod_python程序一般都会有这一行。

def handler(req):

这是处理器方法的声明,它之所以叫"handler"是因为mod_python在指示中使用这个 名字,转换它为小写并移除"python",所以"pythonHandler"变成了"handler",你可以 给它起别的名字,并且通过在指示中使用"::"明确的指定它.举个例子,如果处理器 方法叫"spam",那么指示就应该是”pythonHandler myscript::spam”。

注意处理器必须有一个参数(相当于self?)

request对象。Request对象提供了所有可能用到的信息,比如客户端的IP,头,URI等 等.返回客户端的信息仍然通过request对象传递,注意,在mod_python中没有 response对象。

req.content_type = "text/plain"

这条语句设置文档类型为 "text/plain" 。默认的通常是 "text/html" ,但是因为 我们的处理器不处理任何html, 所以“text/plain”更合适一些。

req.write("Hello World!")

这条语句把字符串” Hello World!”写到客户端(再次强调没有response对象,所以写 到客户端仍然有request对象)。

return apache.OK

这条语句告诉apache一切正常,而且请求也已经被处理了。如果出现异常,这一行 应该返回apache.HTTP INTERNAL SERVER ERROR或返回apache.HTTP FORBIDDEN,而 且apache会在日志中记录这个错误,并产生一条错误信息给客户端。

一些提示:如果你仔细阅读的话,就会发现URI只是指向了myscript.py这个文件, 并没有指定处理器代码执行的顺序,实际上只要告诉处理器需要处理的是一个.py文 件就可以了,文件的名字并不重要,即使URL中指向的文件并不存在.所以,对于上 面的配置,下面两个URL执行的结果是一样的 :

http://myserver/mywebdir/myscript.py
http://myserver/mywebdir/montypython.py

如果你看不懂这段话,重复多看几遍,直到弄懂为止。

现在学习一些更复杂的—认证

现在你已经知道了该怎样写一个简单的处理器,让我们来尝试着写一些更复杂的。 假设我们想用密码保护一个目录,用名字:spam,密码:eggs来登陆。

首先,我们需要告诉apache当需要认证的时候去调用我们的认证处理器。我们通过 在配置文件中加入pythonAuthenHandler来实现,如下:

    <Directory /mywebdir>
       AddHandler mod_python .py
       PythonHandler myscript
       PythonAuthenHandler myscript
       PythonDebug On
    </Directory>

注意,我们在这里为两个不同的处理器指定了相同的脚本,这是可以的,如果你还 记得,mod_python会在同一个脚本中为不同的处理器查找不同的方法,接下来,我 们需要告诉apache我们使用的是最基本的HTTP认证,现在我们的配置文件应该是下 面这样:

    <Directory /mywebdir>
      AddHandler mod_python .py
      PythonHandler myscript
      PythonAuthenHandler myscript
      PythonDebug On
      AuthType Basic
      AuthName "Jian Lee's Web,Auth!"
      require valid-user
    </Directory>

现在我们要在myscript.py中写一个认证处理器方法,一个基本的认证处理器象下面 这样:

    1: from mod_python import apache
    2: def authenhandler(req):
    3:     pw = req.get_basic_auth_pw()
    4:     user = req.user
    5:     if user == "jianlee" and pw == "lijian":
    6:         return apache.OK
    7:     else:
    8:         return apache.HTTP_UNAUTHORIZED
    9: 

让我们一行一行的看这段代码:

def authenhandler(req):

一定是authenhandler。这是处理器方法的声明。为什么这个方法的名字叫 authenhandler呢?这个问题我们在前面已经讲过了,mod_python把配置文件中的指 示的名称(pythonAuthenHandler)去掉"python",然后把剩下的单词全部变成小写,因 此就是authenhandler了。

    pw = req.get_basic_auth_pw()

我们通过这一句代码得到密码。http在传输验证密码的时候一般以base64的编码进 行传输,这个方法把它解析成字符串。

    user = req.user

然后我们通过这一句得到用户名.

    if user == "jianlee" and pw == "lijian":

验证用户是不是我们在前面约定的用户和密码.

        return apache.OK

如果是我们期望的那个用户,那么就返回apache.OK,apache收到以后就会完成这个 请求,处理剩下的步骤。

    else:
        return apache.HTTP_UNAUTHORIZED

如果用户和密码不对,我们就返回HTTP UNAUTHORIZED给客户端,这会在浏览器上显 示。

设置玩,重启apache,在访问这个目录的时候就会出现提示框,请求输入用户名和 密码验证。

发布处理器 — publisher

配置apache使用publisher

我在 /etc/httpd/conf.d/python.conf 配置如下:

LoadModule python_module modules/mod_python.so

Alias /python "/var/www/html/python"
<Directory "/var/www/html/python">
        SetHandler mod_python
        PythonHandler mod_python.publisher
        PythonDebug On
</Directory>

写脚本

默认情况下访问 /var/www/html/python/index.py 脚本,路径是我上面 Alias设置 的。而这个 index.py 脚本中最好有一个 index 方法:

    1: def say(req,what="NOTHING",string="hello"):
    2:   return "I am saying %s , %s !" % (what,string)
    3: 
    4: def index(req,what="Jian Lee"):
    5:   return say(req,what)
    6: 

这样我们在浏览器访问 http://localhost/python 就可以看到 "I am saying Jian Lee ,hello!" 字符串了。

http://localhost/pyhton/say
http://localhost/python/say?what=你的字符串

对于index.py的名字是可以省略的。

参考

中文文档

http://man.chinaunix.net/develop/python/mod_python/mod_python.html