新版本译文出处 -- 河边的小屋

-- oatil, eddyxu [2004-08-09 23:22:00]

mod_python中文文档

mod_python是apache组织的一个项目,通过它,可以开发psp或cgi,mod_python功能强大,速度快,是非常优秀的web开发工具。

第一章 简介

1.1 性能

mod_python的一个最主要优点就是在性能上超越传统CGI。下面是一个非常粗略的测试。该测试是在一台运行Red Hat Linux 7.3的奔腾1.2G的机器上完成的。Ab 用来对4种脚本进行测试,所有的都是从标准cgi模块输入(因为这是一个典型Python cgi脚本开始的方式), 然后输出一个简单的单词"Hello!"。这个结果是基于10000次并发为1的请求。

    Standard CGI:               23 requests/s
    Mod_python cgihandler:     385 requests/s
    Mod_python publisher:      476 requests/s
    Mod_python handler:       1203 requests/s

1.2 适应性

Apache分阶段的处理请求(比方说:读取请求,解析header, 检查存取路径,等等)。这些阶段能被称为"处理器"(handler)的函数实现。传统上, "处理器"是由C语言编写,并编译成Apache的模块。Mod_python提供了一个通过Python写的Apache处理器的来扩展Apache功能的方法。关于Apache请求处理过程的详尽描述,请参阅 Apache API Notes, 也可以参阅 Mod_python - Integrating Python with Apache

为了轻松地从CGI移植,一个标准的mod_python处理器提供了模拟的CGI环境,允许用户在不对代码做任何修改的情况下,使遗留的脚本运行在mod_python下(大多数情况)。

{{{See Also:

http://dev.apache.org/ Apache Developer Resources http://www.modpython.org/python10/ Mod_Python - Integrating Python with Apache, presented at Python 10

}}}

1.3 历史

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

这个Httpdapy的README文件的摘要,很好的阐述了在HTTP server中嵌入Python所带来的挑战和解决方案。

第二章 安装

注意:得到关于安装和其他问题帮助的最好地方是mod_python的邮件列表。请花几分钟,发送一封主题为"subscribe"的e-mail至mod_python-request@modpython.org, 加入mod_python的邮件列表。

2.1 前提条件

为了编译mod_python,你将需要Apache和Python的包含文件(include files),也包括安装在你系统上的Python 的库。如果你是从源码安装的python和Apahce,那么你已经有了所需要的一切。但是,如果你是使用预打包(prepackaged)的软件(比如,Red Hat Linux RPM, Debian, 或者从sunsite得到的Solaris packages,等等),那么很可能你的系统里只有二进制文件而没有源文件。通常,编译mod_python所需要的Apache和Python得包含文件和库文件是分离的"开发"包的一部分。如果你不确定你是否有所有需要的文件,或者从源码编译和安装Python和Apache,或者参考你系统中关于如何得到开发包的文档。

2.2 编译

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

DSO是mod_python现在更流行的并且被推荐的方法。模块被编译为一个共享库,在运行时有服务器动态装入。

DSO的好处是模块安装时不需要重新编译Apache,并且需要时再使用。关于Apahce DSO机制更详尽的描述, http://httpd.apache.org/docs-2.0/dso.html.

现在mod_python只支持DSO。

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

2.2.1 运行 ./configure

./configure脚本将分析你的环境,并且创建为你系统特别定制的Makefiles。除了所有标准autoconf所做的以外,./configure还要作如下的工作:

你可以通过--with-apxs选项,手动指出apxs所在目录,比如:

    $ ./configure --with-apxs=/usr/local/apache/bin/apxs

推荐你指定该选项。

    $ ./configure --with-python=/usr/local/bin/python2.2

2.2.2 开始 make

开始编译,只要简单的输入命令

    $ make

2.3 安装

2.3.1 运行 make install

这部分安装需要以根用户(root)身份进行。

    $ su
    # make install

注意: 如果你希望选择性的仅仅安装Python库文件或者仅安装DSO(这可能不总是需要超级用户权限),你可以用如下的make目标:install_py_lib and install_dso

2.3.2 配置 Apache

如果你将mod_python编译成DSO,那么你需要通过在Apache的配置文件(通常称为httpd.conf 或者 apache.conf)里面加入如下一行,来载入模块:

    LoadModule python_module libexec/mod_python.so

mod_python.so的实际路径可能会变化,但是make install在近结束时会报告mod_python.so的位置和LoadModule目录的形式。

2.4 测试

  1. 使你网站上的某些目录可见,比如,htdocs/test
  2. 在主配置文件或者.htaccess中加入下面几句话。如果你准备使用.htaccess,你就不需要<Directory>标记。(这个目录变成.htaccess文件所在的目录),并且你必须确定应用在这个目录上的AllowOverride至少指定了FileInfo。(默认是None,将无法工作)

    <Directory /some/directory/htdocs/test>
        AddHandler mod_python .py
        PythonHandler mptest
        PythonDebug On
    </Directory>
  1. 如果你改变了主配置文件,你需要重启Apache,以使这些改变生效。
  2. 编辑htdocs/test中的mptest.py文件,使其有如下的代码(从你的浏览器剪切和粘贴的时候要小心,可能会产生错误的缩进和符号错):

   1 from mod_python import apache
   2 
   3 def handler(req):
   4     req.write("Hello World!")
   5     return apache.OK
  1. 将你的浏览器指向mptest.py所在的URL; 你将会看到"Hello World!". 如果你没有看到这些,请参阅下一节"故障排除".
  2. 如果一切顺利,请前进到第三章《指南》。

2.5 故障排除

你可以尝试从如下方面确定问题所在

第三章 指南

现在通过前一章的学习,我们已经学会并安装好mod_python,现在可以通过快速阅读本章进入程序开发阶段。 我强烈推荐你在阅读完本章以后接着阅读(至少是前面的部分)第4章python API的内容。

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

这一节为我们提供了一个快速的关于发布处理器的概况,从而使我们可以不用关注太多的细节就可以写出程序。在这本指南的最后一节,会有一个更详细全面的关于mod_python处理器如何工作的讲解。

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

<Directory D:/apache/Apache2/cgi-bin/oa>
        AddHandler mod_python .py
        PythonHandler mod_python.publisher
        PythonDebug On
</Directory>

(注意:D:/apache/Apache2/cgi-bin/oa是我的机器上的路径)

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

下面是form.html的代码:

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

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

import smtplib
WEBMASTER = "webmaster" # webmaster e-mail
SMTP_SERVER = "localhost" # your SMTP server
def email(req, name, email, comment):
     #确定用户提供了所有的参数
     if not (name and email and comment):
         return "A required parameter is missing, \
             please go back and correct the error"
              # 创建消息对话框

     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>
       亲爱的%s,<br>
       谢谢你的意见,我们会在近期与你联系.
       </html>
    """ % name

    return s

当用户点击确定按钮的时候,发布处理器就会调用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()直接读写客户端等等。

阅读6.1节可以获得更多关于发布处理器的信息.

3.2 快速学习,看一下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动作是读文件并把它发送的客户端。你写的大多数程序都会重载这个处理器。 如果想了解所有的处理器,请查看第5章 apache配置文件指示

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

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

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

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

from mod_python import apache
def handler(req):
   req.content_type = "text/plain"
   req.write("Hello World!")
   return apache.OK

解释一下这个程序:

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”。

注意处理器必须有一个参数


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中指向的文件并不存在.所以,对于上面的配置,http://myserver/mywebdir/myscript.pyhttp://myserver/mywebdir/montypython.py 执行的结果是一样的。

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

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

现在你已经知道了该怎样写一个简单的处理器,让我们来尝试着写一些更复杂的。

假设我们想用密码保护一个目录,用名字: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 "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):

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

pw = req.get_basic_auth_pw()

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

user = req.user

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

if user == "spam" and pw == "eggs":

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

return apache.OK

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

else:
return apache.HTTP_UNAUTHORIZED

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

第四章 Python API

4.1 多解释器

当使用mod_python写程序的时候,很重要的一点就是必须知道python语言的很多特色在写脚本的时候体现不出来。

Python的C API使python具有创建子解释器的能力。在Py newInterpreter()方法的文档中有关于子解释器的更详细的描述。每一个子解释器都有它自己的单独的命名空间,不能被其他的子解释器访问到。子解释器使那些运行在apache服务器中的程序互不干扰。

在启动服务器或初始化mod_python的时候,mod_python会初始化一个叫主解释器的解释器。主解释器有一个字典。最初,这个字典是空的,当发出请求时,子解释器就会被创建,他们的引用也被存储在这个字典中。这个字典使用字符串做为key,作为解释器的名字,这个名字可以是任何字符串。主解释器名叫”main interpreter”.其他解释器的命名方法可以通过 pythonInterp*来控制,这意味着运行在同一个虚拟服务器中所有脚本都在同一个子解释器中执行,但是在不同虚拟服务器中的脚本使用完全不同的命名空间运行在不同的子解释器中。pythonInterpPerDirectory 和 pythonInterpPerDirective 指示改变了一般的命名规则,它们使用绝对路径来访问目录,当然也可以是python*Handler中指定的目录, pythonInterpreter 可以用来强制解释器的名字为一个特殊的字符串从而舍弃习惯上的命名.

一旦被创建,如果子解释器遇到并发请求,那么它就会被重新生成。而不会被销毁,它将一直存在直到apache进程被杀掉。 你可以通过req.interpreter来找到你正在运行的解释器的名字。

4.2 请求处理器

一个处理器就是处理一个请求中的某一步的方法。Apache分步骤处理请求---读请求,处理头,提供内容等等。在每一步中,它都会调用处理器,通过apache的核心或是它的一个模块来提供,比如:mod_python把控制权交给用python写的方法。一个用python写的处理器和一个用c写的处理器完全相同,它有下面的要求: 一个处理器方法必须传递一个request对象的引用。(在本手册中,这个request对象一般都是指req变量) 每一个处理器可以返回:

apache.OK

意思是请求处理的这一步没有错误发生。

apache.DECLINED

意思是请求处理的这一步已经完成,apache需要查看后面的模块中的另一个处理器。

apache.HTTP ERROR

意思是发生了一个http错误,HTTP ERROR可以是下面中的任何一个:

HTTP_CONTINUE = 100
HTTP_SWITCHING_PROTOCOLS = 101
HTTP_PROCESSING = 102
HTTP_OK = 200
HTTP_CREATED = 201
HTTP_ACCEPTED = 202
HTTP_NON_AUTHORITATIVE = 203
HTTP_NO_CONTENT = 204
HTTP_RESET_CONTENT = 205
HTTP_PARTIAL_CONTENT = 206
HTTP_MULTI_STATUS = 207
HTTP_MULTIPLE_CHOICES = 300
HTTP_MOVED_PERMANENTLY = 301
HTTP_MOVED_TEMPORARILY = 302
HTTP_SEE_OTHER = 303
HTTP_NOT_MODIFIED = 304
HTTP_USE_PROXY = 305
HTTP_TEMPORARY_REDIRECT = 307
HTTP_BAD_REQUEST = 400
HTTP_UNAUTHORIZED = 401
HTTP_PAYMENT_REQUIRED = 402
HTTP_FORBIDDEN = 403
HTTP_NOT_FOUND = 404
HTTP_METHOD_NOT_ALLOWED = 405
HTTP_NOT_ACCEPTABLE = 406
HTTP_PROXY_AUTHENTICATION_REQUIRED= 407
HTTP_REQUEST_TIME_OUT = 408
HTTP_CONFLICT = 409
HTTP_GONE = 410
HTTP_LENGTH_REQUIRED = 411
HTTP_PRECONDITION_FAILED = 412
HTTP_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_REQUEST_URI_TOO_LARGE = 414
HTTP_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_RANGE_NOT_SATISFIABLE = 416
HTTP_EXPECTATION_FAILED = 417
HTTP_UNPROCESSABLE_ENTITY = 422
HTTP_LOCKED = 423
HTTP_FAILED_DEPENDENCY = 424
HTTP_INTERNAL_SERVER_ERROR = 500
HTTP_NOT_IMPLEMENTED = 501
HTTP_BAD_GATEWAY = 502
HTTP_SERVICE_UNAVAILABLE = 503
HTTP_GATEWAY_TIME_OUT = 504
HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_VARIANT_ALSO_VARIES = 506
HTTP_INSUFFICIENT_STORAGE = 507
HTTP_NOT_EXTENDED = 510

4.5 apache-----访问apache的内部

python通过一个叫apache的模块来访问apache内部,apache模块放在mod_python包里。这个模块提供了很多访问apache内部构造的对象,很多方法和很多文档。(request对象也有很多访问apache内部的接口,在稍后的request对象那一节我们会讲解。)

apache模块只能在mod_python的脚本中使用,这是因为它是基于mod_python提供的内置的_apache模块。 它这样被引入:

        from mod_python import apache

mod_python.apache定义了下面这些方法和对象。

4.5.1方法

log_error(message[, level, server ])

一个apache ap_log_error()方法的接口,message是承载错误信息的字符串,level是下面常量中的一个:

APLOG_EMERG
APLOG_ALERT
APLOG_CRIT
APLOG_ERR
APLOG_WARNING
APLOG_NOTICE
APLOG_INFO
APLOG_DEBUG
APLOG_NOERRNO

Server是req.server对象的引用。如果server没有被指定,那么错误会被记录到默认的错误日志中,另外它也将被写入到虚拟服务器的错误日志中。如果server没有被指定,那么LogLevel的设置就没有作用,httpd在编译的时候会默认的指定LogLevel,一般使用warn等级。

如果你有一个request对象的引用,那么请使用req.log_error来代替它,它会预先使用请求的格式比如说request的IP来登陆。

Import_module(module name[, autoreload=1, log=0, path=None ])

如果一个模块在上次引入以后改动了,那么我可以利用mod_python的内部机制来自动重新引入这个模块,而这个方法就是达到这个目的的。

module name是一个代表模块名称的字符串,(它可以包含包结构,例如:mypacke.mymoudle); autoreload指明如果从上次引入以后这个模块改动了,那么是否自动重新引入。如果log设为true的话,那么当模块被重新引入的时候,会有一条信息自动记载到日志中,path允许重新指定模块所在的路径。 举个例子:

                from mod_python import apache
                mymodule = apache.import_module(’mymodule’, log=1)

allow_methods([*args ])

一个设置req.allowed的非常方便的方法,req.allowed被用来构造”allow”头,它应该在返回一个HTTP NOT IMPLEMENTED错误以前就设置好。 参数可以是下面列表中的一个或多个:

M_GET
M_PUT
M_POST
M_DELETE
M_CONNECT
M_OPTIONS
M_TRACE
M_PATCH
M_PROPFIND
M_PROPPATCH
M_MKCOL
M_COPY
M_MOVE
M_LOCK
M_UNLOCK
M_VERSION_CONTROL
M_CHECKOUT
M_UNCHECKOUT
M_CHECKIN
M_UPDATE
M_LABEL
M_REPORT
M_MKWORKSPACE
M_MKACTIVITY
M_BASELINE_CONTROL
M_MERGE
M_INVALID

Config_tree()

返回服务器的配置树。这个树不包括来自.htaccess文件的指示。这是一个源文件的拷贝,请注意修改它对源文件没有作用。

Server_root()

返回ServerRoot.的值。

Make_table()

这个方法已经被废弃了,现在一般使用table(在后面)

mpm_query(code)

这个方法允许MPM的查询可以访问各种不同的参数,比如进程或线程的数量。返回值是下面三个常量中的一个:

AP_MPMQ_NOT_SUPPORTED = 0 #这个值指定一个MPM是否有能力执行线程或分线程。
AP_MPMQ_STATIC = 1 # 这个值指定一个MPM是否有能力使用静态线程或后台程序。
AP_MPMQ_DYNAMIC = 2 #这个值指定一个MPM是否有能力使用动态线程或后台程序。

code参数的值必须要是下面常量中的一个:

AP_MPMQ_MAX_DAEMON_USED = 1 # 到目前为止使用的最大数目的线程。
AP_MPMQ_IS_THREADED = 2 # MPM 可以执行线程。
AP_MPMQ_IS_FORKED = 3 #  MPM可以做分支。
AP_MPMQ_HARD_LIMIT_DAEMONS = 4 #  已经编译的最多的线程。
AP_MPMQ_HARD_LIMIT_THREADS = 5 # The compiled max # threads
AP_MPMQ_MAX_THREADS = 6 # 执行的最大线程数。
AP_MPMQ_MIN_SPARE_DAEMONS = 7 #  最小空闲后台线程数。
AP_MPMQ_MIN_SPARE_THREADS = 8 #   最小空闲线程数。
AP_MPMQ_MAX_SPARE_DAEMONS = 9 #   最大空闲后台线程数。
AP_MPMQ_MAX_SPARE_THREADS = 10 #  最大空闲线程数
AP_MPMQ_MAX_REQUESTS_DAEMON= 11 # 每个进程的最大请求数
AP_MPMQ_MAX_DAEMONS = 12 #  设置后台进程运行的最大数。

举个例子:

                if apache.mpm_query(apache.AP_MPMQ_IS_THREADED):
                # 一些代码
                  else:
                # 执行另一些代码

4.5.2 table对象(mp_table)

class table([mapping-or-sequence ])

返回一个空的type mp_table.对象。查看4.5.2查看table对象的描述。 序列化映射会为table提供初始值。

Table对象是apache APR table的一个包裹类。Table对象的行为非常象字典。(包括python2.2版本新加的一些特色,比如支持操作者等等),但有下面的不同:

1. 键和值必须都是字符串。

2. 键看起来好象没有状态。

3. 允许相同的键(看下面的add()方法),如果有一个键有好几个值的话,那么它们就被存放在一个列表中。 Apache使用的大多数信息存储在table中,例如,req.headers_in和req.headers_out。

Mod_python提供的所有tables实际上映射了apache的内部构造。所以改变了python的table也就潜在的改变了apache的table。在类似于字典的行为的基础上,table对象还增加了一个方法:

add(key, val)

addl)允许创建重复的键,这对于多头是非常有用的,比如 Set-Cookie: 被请求。 Add()方法是3.0版本中新加的。

4.5.3 request对象

request对象是映射到Apache request_rec结构。当一个处理器被调用的时候,经常只传递一个单独的参数


request对象。

你可以通过动态的给它增加属性来达到在处理器之间传递属性的目的。

Reuqest的方法:

Add_common_vars()

调用 Ap_add_common_vars()方法,在调用这个方法以后,req.subprocess_env 会包括很多CGI的信息。

Add_handler(htype, handler[, dir ])

允许动态的进行处理器的注册。htype

4.8 Session—会话管理

Sessio模块提供给对象在请求之间穿越并保持持久状态的能力。

这个模块包括BaseSession类,它并不是直接来使用的(它对于存储 session来说没有任何作用).还有一个DbmSession类,它使用dbm来储存会话。

BaseSession类也提供了会话锁,它可以跨越进程和线程。

第五章 Apache配置文件指示

5.1 请求指示

5.1.1 Python*Handler指示的语法

所有的请求指示语法都是下面这样:

Python*Handler handler [handler ...] [ | .ext [.ext ...] ]

[Handler]的位置只接受一个参数-request对象,ext的位置是文件的扩展名。

多个处理器可以在一行中指定,在这种情况下他们会从左到右被连续调用。同一个处理器可以被指定好多次,这都遵循一个结果-在列表中的多个处理器会被连续调用,从第一个知道最后一个。如果其中一个处理器没有返回apache.OK,那么它后面的那些处理器就会停止执行。

这个处理器列表后面可以跟着 一个“|”符号和文件扩展名,这样可以限定处理器只处理这个列表中标明的文件。 一个处理器有下面的语法:

module[::object]

module的位置应该是一个模块的完整名称(包的”.”也可以),可选择的参数object代表的是在模块内的一个对象的名字。Object也可以包含有”.”符号,在这种情况下它被从左到右执行,在解决的过程,如果mod_python发现一个类,那么它会尝试实例化这个类,并传递一个request对象给它。

如果object没有指定,它会默认的指定为handler的名称,并去掉”python”,举个例子,PythonAuthenHandler的默认的object应该是authenhandler.

例如:

        PythonAuthzHandler mypackage.mymodule::checkallowed

查看更多关于处理器的信息,请阅读处理器概览

小提示:选择”::”是出于性能上的考虑。为了使python可以使用模块中的对象,这个模块首先需要被引入。使用一个单独的”.”,与其花费时间让程序判断每一个单词是一个包,模块还是类等等,不如使用一个非python的符号,比如”::” ,这样会是mod_python有一定的性能提升。

5.1.2 PythonPostReadRequestHandler

语法: Python*Handler
上下文关系:服务器配置,虚拟主机
重载:无
模块: mod python.c

当request被请求以后在其他步骤执行以前,这个处理器会被调用。这对于决定一个基于输入头的域是非常有用的。 注意:当reuqest的这一步执行完以后,URI还没有被解析为一个路径名称。

5.3 连接处理器

5.3.1 PythonConnectionHandler

语法:PythonConnectionHandler handler
用于:服务器配置
模块:mod python.c

指定使用哪一个处理器来处理连接,handler会传递一个单独的参数-connection对象。

Handler是一个模块的名字后面跟”::”符号然后是一个对象的名字,如果对象名字没有写,那么默认的是connectionhandler’。

5.4 其他指示

5.4.9 PythonOptimize

语法:PythonOptimize {On, Off}
默认:PythonOptimize Off
用于:服务器配置
模块:mod python.c

允许python优化,和Python -O 命令一样。

5.4.10 PythonOption

语法:PythonOption key value
用于:服务器配置,虚拟主机,字典,htaccess
重载:无
模块:mod python.c

分配一个键和值给一个table,从而可以在以后通过req.get options()重新找到。这对于在apache配置文件(‘httpd.conf’, ‘.htaccess’等等)和python之间传递信息非常有用。

第六章 标准处理器

6.1 发布处理器

发布处理器是一个很好的方法来避免你自己去编写处理器,从而使你可以集中精力进行快速开发。它是从Zope的Zpublisher得到灵感而产生的。

6.1.1 介绍

为了使用发布处理器,你需要在你的配置文件中写入下面的语句:

  <Directory /some/path>
    SetHandler mod_python
    PythonHandler mod_python.publisher
  </Directory>

这个处理器使你可以通过URL来访问模块中的方法.例如,如果有下面这个模块,名叫”hello.py”:

def say(req, what="NOTHING"):
    return "I am saying %s" % what

那么URL http://www.mysite.com/hello.py/say 就会返回"I am saying NOTHING".http://www.mysite.com/hello.py/say?what=hello 则会返回"I am saying hello".

6.1.2 发布处理器的规则

6.1.3 表单数据

在匹配参数列表的过程中,发布处理器会创建一个 fieldStorage 类的实例.这个实例的引用存储在request对象的一个属性中.因为一个 fieldStorage 在一个 request 中只能实例化一次,所以在使用发布处理器的时候不要实例化 fieldStorage 而使用 request.form 代替.

6.2 PSP处理器

PSP 处理器是用来处理那些使用mod_python.psp模块中的PSP类来写的文档。为了使用它,只要简单的在你的httpd配置文件中加入下面的语句就可以了:

AddHandler mod_python .psp
PythonHandler mod_python.psp

需要更多关于PSP语法的细节,请阅读4.9小节。

如果pythonDebug 设置为On的话,那么通过在URL后面加一个下划线(“_”),你就可以得到psp模块的python代码,这在测试的时候是非常有用的。

A. Changes from Previous Major Version (2.x)

Mod_python 3.0 不再支持 Apache 1.3.x 版本,仅支持 Apache 2.x 版本

Mod_python 不支持 Python 2.2.1以前的版本

Mod_python 现在支持 Apache Filters 。

Mod_python 现在支持 Apache 连接句柄

Request Object 现在支持 internal_redirect(). (内部重定向)

Connection Object 拥有 read(),readline() , write()方法

Server Object 拥有 get_config().方法

Httpdapi 句柄被删除

Zpublisher句柄被删除

Username is now in req.user instead of req.connection.user

Mod_python Tip

mod_python 3.1.3 版本不能正确upload file 的解决办法

    def __getitem__(self, key):
        """Dictionary style indexing."""
        if self.list is None:
            raise TypeError, "not indexable"
        found = []
        for item in self.list:
            if item.name == key:
                if isinstance(item.file, FileType) or \
                       isinstance(getattr(item.file, 'file', None), FileType):
                    found.append(item)
                else:
                    found.append(StringField(item.value))
        if not found:
            raise KeyError, key
        if len(found) == 1:
            return found[0]
        else:
            return found

modpythoncn (last edited 2009-12-25 07:17:06 by localhost)