Mod_python 3.2.8中文手册(二)
codebreaker
|
1#
codebreaker 发表于 2008-06-20 14:39
Mod_python 3.2.8中文手册(二)第四章 Python API 4.1多解释器 使用mod_python工作的时候应该理解,并不是使用Python在命令行下写脚本,而是用Python调用C语言API。 Python的C语言API提供了创建子解释器的能力。关于子解释器的更多信息详见Py_NewInterpreter()函数。在这里,每个子解释器拥有独立的命名空间,并与其他子解释器不可访问。子解释器非常适合于理解同一个服务器中处理各个请求的进程。 服务器启动mod_python的时候会启动一个主解释器。主解释器包含子解释器词典。刚开始词典是空的。对应每一个请求就会创建一个子解释器,并将引用存储在词典里。这个词典用解释器名作为键名,主解释器叫做'main_interpreter'。其他的解释器受到PythonInterp*的控制。缺省的行为是使用apache虚拟服务器名来命名(ServerName标志)。这意味着同一个虚拟服务器中的脚本在同一个子解释器中执行,但不再同一个虚拟服务器中的脚本因为不同的子解释器而无法互相访问。 PythonInterpPerDirectory和PythonInterpPerDirective标志改变(alter)命名惯例(convention)到要存取的绝对路径,或者在Python*Handler可以访问到的地方,分别的(respectively)。PythonInterpreter能够强制使用解释器名重载所有的命名惯例。 一旦创建,一个子解释器将会被接踵而来的请求重用,在apache停止之前不会被销毁。从调用req.interpreter可以获取当前的解释器名。 参考Python的C语言API: http://www.python.org/doc/current/api/api.html 4.2请求(request)处理器 一个请求处理器是处理请求阶段细节的处理器。apache在处理请求的每一个阶段都对调用相应的处理器。对每一个阶段都会调用请求处理器,由apache的核心或者模块提供,比如mod_python由用户的Python函数提供。用Python书写的处理器只要遵守如下规则就与C写的没有区别: 处理器函数总是会传递请求对象的引用,一般是req变量。 每个处理器可以返回如下:
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 205 HTTP_PARTIAL_CONTENT 206 HTTP_MULTI_STATUS 207 HTTP_MULTIPLE_CHOICES 300 HTTP_MOVED_PERMANENTLY 301 HTTP_MOVEDTEMPORARILY 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 可以通过抛出apache.SERVER_RETURN异常来返回错误码,并将HTTP错误码作为异常的参数。例如: raise apache.SERVER_RETURN, apache.HTTP_FORBIDDEN 处理器可以通过req.write()方法将文档发送到客户端。 客户端提交的数据可以通过req.read()读取。 注意:Python*Handler所在的目录必须已经在sys.path中,如果没有在配置段指定则不会在。 一个请求处理器的例子: from mod_python import apache def requesthandler(req): req.content_type='text/plain' req.write('Hello World!') return apache.OK 4.3过滤(filter)处理器 过滤处理器可以改变服务器的输入和输出。分两种:输入和输出的过滤。现在mod_python仅提供请求级别(request-level)的过滤器,就是HTTP的请求和回应体可以被过滤。未来的apache将会提供连接级别(connection-level)的过滤器。 过滤处理器接收一个filter对象做参数,请求对象可经由此得出filter.req,但是所有的读写动作必须经由filter的方法。 过滤器在读到None时需要被关闭,代表流的结束。过滤器的返回值将会被忽略,但可用filter.pass_on()方法达到同样的效果。 过滤器必须一开始就注册为PythonInputFilter或PythonOutputFilter,然后添加到apache的配置标志Add/SetInputFilter或Add/SetOutputFilter。 如下例子把所有.py结尾文件用CAPITALIZE过滤器处理,如下是配置: PythonOutputFilter capitalize CAPITALIZE AddOutputFilter CAPTITALIZE .py 如下是文件capitalize.py的内容: from mod_python import apache def outputfilter(filter): s=filter.read() while s: filter.write(s.upper()) s=filter.read() if s is None: filter.close() 书写过滤器时应该注意到过滤器随时都会被调用。过滤器无法控制数据的总量,也无法确定请求何时调用。比如对于一个请求,过滤器可能会执行一次或五次,并无法知晓调用何时结束和先后顺序。从一个read操作返回的EOS代表请求的结束。 过滤器也可能在子请求的递归调用中。为避免数据多次被改变,经常的确保并不在子请求中,依靠req.main变量值。 4.4连接(connection)处理器 连接处理器处理连接到服务器的TCP连接。不同于HTTP处理器,连接处理器接收connection对象做参数。连接处理器可以用于实现协议。如下例配置: PythonConnectionHandler echo 实现文件echo.py: from mod_python import apache def connectionhandler(conn): while 1: conn.write(conn.readline()) return apache.OK 4.5apache-访问Apache内部 apache内部对Python的接口也恰好叫做apache,在mod_python包。提供了连接apache内部的重要功能,比如有用的函数,文档等(request对象也提供访问Apache内部的接口,但不在本节)。 apache模块仅可作为mod_python下的一个脚本来导入,因为它依赖于mod_python内建的_apache模块。最好按照如下导入: from mod_python import apache mod_python.apache模块定义了如下函数和对象,更多深入的信息查看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没有指定时,日志级别也无效,日志级别是httpd在编译时指定的,经常为warn。 如果拥有请求对象的引用,最好用req.log_error,这样将会存入请求相关信息,如源IP等。 import_module(module_name[,autoreload=1,log=0,path=None]) mod_python的内部高级特性,用于在模块改变时自动重新载入模块。 module_name是模块名,可以包含点的包名。 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 exists_config_define(name) 确定Apache是否存在一个name配置。比如Apache定义了-DFOOBAR则如下测试为真: apache.exists_config_define('FOOBAR') register_cleanup(handler[,data]) 注册一个清除行为,等同于req.register_cleanup()或reg.server.register_cleanup(),除非服务器或请求对象不需要。 config_tree() 返回服务器级(server-level)配置树。这些配置不包含.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是否可用fork生成子进程 AP_MPMQ_HARD_LIMIT_DAEMONS=4 编译时允许的最大守护进程数量 AP_MPMQ_HARD_LIMIT_THREADS=5 编译时允许最大线程数量 AP_MPMQ_MAX_THREADS=6 threads/child配置允许的最大线程数量 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): # do something else: # do something else 4.5.2表格对象(mp_table) class table([mapping-or-sequence]) 返回一个新的mp_table表格对象。mapping-or-sequence提供了表格的初始化数据。表格对象是对APR表格对象的包装(wrapper)。表格对象的行为(behave)非常像词典(还支持Python2.2以后的in操作符),但是有以下不同:
很多apache的信息存储在表格中,如req.headers_in和req.headers_out。mod_python提供的所有表格对象都是真正(actual)映射(mapping)到apache结构的,所以改变表格的值也会改变apache的表格。 除了(in addition to)像词典一样的行为(behavior)之外,表格对象还支持如下操作: add(key,val) 这个方法允许使用相同的键,这对重复的头很有用,比如"Set-Cookie:"就需要。这个功能从3.0开始提供。 4.5.3请求对象 请求对象是映射到apache的request_rec结构的对象。当处理器被调用时,会传递唯一个的一个参数就是请求对象。可以为请求对象指定属性,用于在处理器之间通信。如下是方法: add_common_vars() 间接调用ap_add_common_vars()函数。调用后,req.subprocess_env会包含大量的CGI信息。 add_handler(htype,handler[,dir]) 允许动态注册处理器。htype是要添加的处理器的标志,如'PythonHandler',但不可以是过滤器(filter)或连接(connection)。handler是包含模块名或函数名的处理器函数。可选参数dir是需要添加到pythonpath环境变量的路径。如果未指定目录,而且有同类型的处理器,则继承路径,否则用前一路径。如果有PythonPath标志存在,则sys.path将会设置为它。 通过这种方式添加的处理器生存期为这个请求。为同一个类型添加多个处理器是很有用的,不过要注意避免死循环(infinite loop)。 动态注册处理器是一种很有用的技术,比如用于PythonAuthenHandler,可以为不同的认证级别指定不同的权限。如: if manager: req.add_handler("PythonHandler","menu::admin") else: req.add_handler("PythonHandler","menu::basic") 注意,如果传递了一个无效处理器,则会在寻找处理器时发生异常。 allow_methods(methods[,reset]) 添加方法到req.allowed_methods列表。这个列表将会允许传递,在头部指定HTTP_METHOD_NOT_ALLOWED或HTTP_NOT_IMPLEMENTED返回到客户端。注意apache并不会对这些方法起作用。这个列表仅仅用于构造头部。实际的方法处理逻辑在处理器代码中提供。 methods是一个字符串列表,如果reset设置为1,则列表会被清空。 document_root() 返回DocumentRoot设置 get_basic_auth_pw() 返回简单认证时的密码字符串 get_config() 返回包含mod_python配置的表格对象的引用,用于当前请求,除了Python*Handler和PythonOption(可以通过req.get_options()获得)。表格包含键,和值列表。 get_remote_host([type,str_is_ip]) 用于查询客户端的DNS名和IP地址,首次调用时查询DNS,其后的查询返回缓存数据。 可选参数type可为如下值: apache.REMOTE_HOST:查询DNS名,当apache标志HostNameLookups为off时返回None,无法查询。 apache.REMOTE_NAME:缺省值,尽可能返回DNS名,否则返回IP地址字符串。 apache.REMOTE_NOLOOKUP:不执行DNS查询,直接返回IP地址。如果曾经执行过查询,则返回缓存的机器名。 apache.REMOTE_DOUBLE_REV:强制使用double-reverse查询,失败返回None。 如果str_is_ip设为None或未指定,则返回值为DNS名或IP地址的字符串。如果str_is_ip不为None,则返回一个(address,str_is_ip)元组。当str_is_ip为非零则address为IP地址字符串。失败返回None。 get_options() 返回PythonOptions标志的选项表格的引用。 internal_redirect(new_uri) 对请求进行内部重定向。new_uri是字符串。内部重定向将会创建一个新的请求对象,并执行所有的阶段。req.prev包含重定向之前的地址。 log_error(message[,level]) 对apache函数ap_log_error()函数的接口。message是日志信息,level是日志级别标志,可为如下值: APLOG_EMERG APLOG_ALERT APLOG_CRIT APLOG_ERR APLOG_WARNNING APLOG_NOTICE APLOG_INFO APLOG_DEBUG APLOG_NOERRNO 如果需要写入日志而不是通过请求对象,可用apache.log_error函数。 meets_conditions() 调用apache函数ap_meets_conditions()返回状态码。如果status是apache.OK,则响应正确。如果不是则简单的返回状态码status。注意req.headers_out将会被优先(prior)设置,并也会影响req.status的值,假如不是返回apache.OK。 例如: ... r.headers_out['ETag']="1130794f-3774-4584-a4ea-0ab19e684268" r.headers_out['Last-Modified']='Wed, 23 Feb 2005 00:00:00 GMT' r.headers_out['Expires']='Mon, 18 Apr 2005 17:30:00 GMT' status=r.meets_conditons() if status!=apache.OK: return status ... 处理响应内容 ... requires() 返回包含require标志参数的元组。例如如下apache配置: AuthType Basic require user joe require valid-user 函数将会返回('user joe','valid-user') read([len]) 从客户端读取最多len字节的数据,返回字符串数据。如果len为负数(negative)或者缺省(omitted),则读取所有的数据。这个函数也会受到apache配置标志Timeout的影响,如果读取时超时则会终端,并抛出IOError异常。 这个函数依赖于(rely的复数relies)客户端提供的Content-length头。如果未提供这个头,则缺省为0。不正确的Content-length将会导致函数试图读取更多的数据,并且在超时到达之前一直出于阻塞状态。 readline([len]) 像read()一样读取到行尾。注意,同HTTP定义一样,大多数客户端的行结束是'\r\n',而不是简单的'\n'。 readlines([sizehint]) 读取sizehint字节以内的所有行,并返回行列表。 register_cleanup(callable[,data]) 注册一个清理行为。参数callable可以为任何可调用对象,可选参数data可以是任何对象,缺省为None。在每个请求结束的时候,而在请求对象被销毁之前,callable将会被调用,并且传递一个唯一的参数data。 推荐传递请求对象作为data,但是注意,在执行清理行为时,请求对象的处理已经完成,这时再对客户端进行写操作是无意义的(pointless)。 如果在执行清理时遇到(encounter)错误,将会被日志记录。除非直接影响请求处理,否则执行清理中的bug很难辨认(spot)。 如果在清理行为之前,服务器关闭了,则很可能不会被执行。 sendfile(path[,offset,len]) 发送path文件到客户端,开始为offset,并发送len字节。offset缺省为0,而len缺省为-1,发送整个(entire)文件。 返回成功发送的字节数,或者在出错时抛出IOError异常。这个函数提供了向客户端发送文件的最有效(most efficient)的方式。 write(string[,flush=1]) 将字符串立即(directly)写入客户端,然活清空(flush)缓存,除非flush是0。 flush() 将缓存数据写入客户端,并清空缓存。 set_content_length(len) 设置req.length和"Content-length"头。注意必须在任何发送数据之前设置,比如req.write()之前,否则是无意义的(meaningless)。
connection 这个请求的连接对象。查看后面的详细介绍。只读。 server 请求所属的服务器对象。查看后面的详细介绍。只读。 next 如果是内部重定向,重定向到的请求对象。只读。 prev 如果是内部重定向,来自重定向的请求对象。只读。 main 如果这是一个子请求,指向主请求。只读。 the_request 包含请求的第一行的字符串。只读。 assbackwards 指定HTTP/0.9的简单请求。这意味着响应不包含任何头,仅包含信息主体。用于兼容古老的浏览器。也可以指定这个选项用于在重定向中避免(avoid)发送头。 proxyreq 代理请求。一个apache.PROXYREQ_*值。只读。 header_only 指定HEAD请求的布尔变量,反对GET。只读。 protocol 客户端提供的协议,或者是'HTTP/0.9'。同CGI SERVER_PROTOCOL。只读。 proto_num 整数,协议版本号,比如1.1对应1001。只读。 hostname 字符串,由URI或Host:设置,头。只读。 request_time 长整数,请求发生的时间。只读。 status_line 状态行,如'200 OK'。只读。 status 状态,apache.HTTP_*中的一个值。 method 包含方法的字符串,如'GET','HEAD','POST'。同CGI REQUEST_METHOD。只读。 method_number 方法号,整数。只读。 allowed 整数,允许方法的位逻辑。使用允许结构:头响应HTTP_METHOD_NOT_ALLOWED或HTTP_NOT_IMPLEMENTED。这个字段是apache内部使用的。需要设置则使用req.allow_methods()方法。只读。 allowed_xmethods 元组,允许的扩展(extension)方法。只读。 allowed_methods 元组,允许的方法,使用METHOD_NOT_ALLOWED的关系。这个成员无法被req.allow_methods()方法修改。只读。 sent_bodyct 整数,正文的字节数。只读。 bytes_sent 长整数,已经发送的字节数。只读。 mtime 长整数,资源的修改时间。只读。 chunked 传送大块数据时的编码,布尔值。只读。 range 字符串'Range:'头。只读。 clength 长整数,真正的正文长度。只读。 remaining 长整数,等待读取的数据字节数,只在一个读取操作中有效,只读。 read_length 长整数,已经读取的字节数,只读。 read_body 整数,请求体怎样被读取,只读。 read_chunked 布尔值,读取大块数据的编码。只读。 expecting_100 布尔值,是否客户端需要等待100(HTTP_CONTINUE)响应,只读。 headers_in 客户端发来的头的表格对象。 headers_out 需要发送给客户端的头的表格对象。 err_headers_out 当出错时需要发送的头的表格对象,用于出错时替换headers_out。 subprocess_env 包含CGI信息的表格对象。在需要信息之前需要先调用req.add_common_vars()方法来填充信息。 notes 与请求拥有共同生存期的对象,用于存储各种信息,可以在一个请求的各个处理器之间传递信息。如果确实需要在各个处理器之间传递信息,最好的方式是给请求对象添加成员。 phase 正在处理的阶段,比如'PythonHandler',只读。 interpreter 正在运行的子解释器名。 content_type 字符串,正文类型。mod_python维护一个内部标志(req._content_type_set)来保持content_type的设置。发布器按照如下方式使用这个标志:当content_type没有明确(explicitly)的设置时,它依靠输出的前几个字节来猜测(attempt)。 content_languages 元组。用字符串列表表示正文的语言。 handler 当前处理器的名字。由mod_mime设置,而不是mod_python处理器。大多数情况还是'mod_python',只读。 content_encoding 字符串,正文编码,只读。 vlist_validator 整数,有效变量的列表(如果为负数),只读。 user 获取验证的用户名。同CGI REMOTE_USER,只读。注意,req.get_basic_auth_pw()必须在此之前调用(be called prior)。 ap_auth_type 验证类型,同CGI AUTH_TYPE,只读。 no_cache 布尔值,如果为true则没有缓存,只读。 no_local_copy 布尔值,如果没有本地副本,只读。 unparsed_uri URI没有经过任何转换,只读。 uri URI的一部分路径,只读。 filename 请求的文件名字符串。 canonical_filename 字符串,真实的文件名(req.filename是有效的,如果她们不同)。只读。 path_info 字符串,在文件名之后,查询参数之前的部分。同CGI PATH_INFO。 args 字符串,同CGI QUERY_ARGS,只读。 finfo 元组,文件信息结构,类似于POSIX状态,URI指向的文件的信息(mode,ino,dev,nlink,uid,gid,size,atime,mtime,ctime,fname,name)。模块apache定义了FINFO_*变量的常量,可用于存取其中的元素,如: fname=req.finfo[apache.FINFO_FNAME] 只读。 parsed_uri 元组,被分解开的URI:(scheme,hostinfo,user, password, hostname, port,path,query,fragment)。模块apache定义了URI*常量用于存取元组的元素,如: fname=req.parsed_uri[apache.URI_PATH] 只读。 used_path_info 当前请求中被拒绝(reject)的path_info,只读。 eos_sent 布尔值,是否发送过EOS,只读。(EOS=end of stream) 4.5.4连接对象(mp_conn) 连接对象是apache的conn_rec结构的映射。 连接对象的方法: read([length]) 从客户端读取最多length字节的数据。在读到任何数据之前将会阻塞。如果length是-1,则读取直到套接字关闭,就是HTTP服务器代码的EXHAUSTIVE模式。仅可在连接处理器中使用。 注意从3.0.3版本开始,这个方法的行为有所改变,在此前是阻塞读取直到length个字节读取完成。 readline([length]) 读取一行,最多到length个字节。 仅可在连接处理器中使用。 write(string) 向客户端写入字符串。仅可在连接处理器中使用。 连接对象的成员: base_server 连接通过的虚拟主机,只读。 local_addr 服务器的地址元组(address,port),只读。 remote_addr 客户端地址元组(address,port),只读。 remote_ip 客户端的IP地址,同CGI REMOTE_ADDR,只读。 remote_host 字符串,客户端的DNS名称,如果没有检查DNS则返回None,如果没有名字则返回""。同CGI REMOTE_HOST,只读。 remote_logname 远程的名字,如果使用了RFC1413识别信号(ident)。同CGI REMOTE_IDENT,只读。 aborted 布尔值,如果连接被中断则为真,只读。 keepalive 整数,1代表连接保持到下一个请求,0代表未定,-1代表严重错误,只读。 double_reverse 整数,1代表执行反向DNS查询,0代表未启用,-1代表查询失败,只读。 keepalives 连接被使用过的次数,只读。 local_ip 本机的服务器IP地址,只读。 local_host 服务器的DNS名称,只读。 id 长整数,一个唯一的连接ID,只读。 notes 表格对象,包含各种与连接具有相同生命周期的信息。 4.5.5过滤器对象(mp_filter) 过滤器对象控制mod_python的输入输出,通常用于提取信息,获取信息并存入过滤器栈。 过滤器的方法: pass_on() 不处理任何数据,全部放行。 read([length]) 从临近过滤器至多读取length个字节的数据,返回字符串数据,如果读取流结束则返回None。过滤器在遇到EOS之后必须关闭。如果未指定length或为负数,则读取当前所有有效数据。 readline([length]) 读取一行至多length个字节。 write(string) 将字符串写入临近的过滤器。 flush() 将缓存输出到FLUSH缓存桶。 close() 关闭过滤器,并发送EOS标志。之后关于这个过滤器的IO操作会抛出异常。 disable() 告知mod_python忽略处理器并让数据放行。在mod_python内部使用打印栈跟踪,防止进入死循环。 过滤器成员: closed 布尔值,指示过滤器是否关闭,只读。 name 字符串,过滤器的注册名,只读。 req 请求对象的引用,只读。 is_input 布尔值,如果是一个输入过滤器则为True,只读。 handler 字符串,配置中的处理器名称,只读。 4.5.6服务器对象(mp_server) 请求对象映射到apache的request_rec结构。服务器结构描述了服务器(也可能是虚拟服务器)如何处理请求。 服务器方法: get_config() 类似于req.get_config(),但返回指向server->module_config的配置向量。 register_cleanup(request,callable[,data]) 注册一个清除行为。类似于req.register_cleanup(),除了在子结束时间以外(字句不通)。这个函数需要一个额外的参数-请求对象。 服务器成员: defn_name 字符串,配置文件中服务器定义名,只读。 defn_line_number 整数,服务器定义所在配置文件的行号,只读。 server_admin ServerAdmin标志的值,只读。 server_hostname ServerName标志的值,同CGI SERVER_NAME,只读。 names 元组,ServerAlias标志的列表,不包含通配符,用wild_names分隔,只读。 wild_names 元组,ServerAlias标志的通配服务器名,只读。 port 整数,TCP/IP端口号,同CGI SERVER_ROOT。在apache2.0开始只是显示为0,可以查看req.connection.local_addr。只读。 error_fname 错误日志文件的文件名,只读。 loglevel 整数,日志级别,只读。 is_virtual 布尔值,如果是一个虚拟服务器则为True,只读。 timeout 整数,Timeout标志的值,只读。 keep_alive_timeout 整数,保持连接的超时时间,只读。 keep_alive_max 每个连接最大允许的请求数,只读。 keep_alive 保持连接?只读。 path 字符串,ServerPath标志的值,服务器路径,只读。 pathlen 整数,路径长度,只读。 limit_req_line 整数,HTTP请求行的长度限制,只读。 limit_req_fieldsize 整数,请求头的长度限制,只读。 limit_req_fields 整数,请求头的字段数量限制,只读。 4.6util-工具箱 util模块提供了类似于cgi模块的多种实用工具。util模块的实现也是非常有效率的,直接调用Apache的API,并且通过环境变量传递信息。 推荐的使用这个模块的方式: from mod_python import util 参考CGI文档: http://CGI-spec.golux.com 4.6.1FieldStorage类 通过FieldStorage类传递数据,这个类类似于标准模块cgi FieldStorage。 class FieldStorage(req[,keep_blank_values,strict_parsing]) 这个类提供了处理从客户端提交的HTML。req是mod_python请求对象的实例。 可选参数keep_blank_values是一个标志选项,判定是否把从数据编码而得的URL中的空值作为空字符串处理。缺省值为False,代表忽略空值,好像他们没有出现过一样。 可选参数strict_parsing还没有实现。 初始化时,FieldStorage类读取所有从客户端提交的信息。当所有客户端信息处理完成时,只剩下一个对应一个请求的FieldStorage类的实例。你也可以尝试在FieldStorage实例化之前和之后访问客户端数据。 从客户端读取的数据将会被转换成Field对象,每项数据一个字段。从HTML提交的输入类型file,将会被以临时文件的形式稍后提交成Field对象的file属性。 FieldStorage类有一个映射对象接口,可以作为词典来处理。当使用映射时,键名是输入字段名,返回的词典值可能是如下的:
注意:不同于标准库cgi模块的FieldStorage类,一个Field对象只能返回上传文件。其他情况返回StringField的实例。这意味着不需要使用.value属性就可以存取字段值,在大多数时候。 除了普通的映射对象方法(指词典),FieldStorage对象还有如下属性: list 这是Field对象的列表,对应每个输入。如果具有同名的多个输入,则列表中也会拥有多个对象。 FieldStorage类的方法: getfirst(name[,default]) 总是返回表单数据名name的一个值。如果没有对应的字段则返回default指定的值。缺省返回None如果未指定default。 getlist(name) 返回表单字段name的值列表。如果没有对应字段则返回空列表。即使只有一个值也会返回包含这个值的列表。 4.6.2Field类 class Field() 这个类用于FieldStorage的内部实现。每个Field类实例对应一个HTML表单的输入。 Field实例包含如下属性: name 输入名 value 输入值。这个属性用于读取数据上传文件的数据。但是注意处理大文件,因为整个文件都会被读入内存。 file 类似文件对象,指向上传的临时文件TemporaryFile实例。(更多信息参考python标准tempfile模块中的TemporaryFile类) 简单的来说,它是一个StringIO对象,所以你可以使用这个属性读取字符串值来更好的代替value属性。 filename 客户端提供的文件名。 type 客户端提交的content-type内容类型。 type_options 真实的内容类型,从客户端提交头的content-type提供的。这是一个词典。 disposition 提交头的content-disposition的第一部分的值。 disposition_options 提交头的content-disposition的第二部分的值,词典。 参考: RFC1867,HTML表单提交文件,"Form-based File Upload in HTML" 4.6.3其他函数 parse_qs(qs[,keep_blank_values,strict_parsing]) 这个函数的功能等同于标准库cgi parse_qs,但是是用C语言写的,运行更快。 转换一个query字符串(URL中附加的提交数据)作为字符串参数。数据以词典返回。词典的键名是query变量的变量名,值是对应变量的值的列表。 可选参数keep_blank_values是一个标志变量指定URL编码中的空值是否作为空字符串处理。True指定空值转换为空白字符串。缺省值是False指定空值被忽略。 注意:strict_parsing参数尚未实现。 parse_qsl(qs[,keep_blank_values,strict_parsing]) 这个函数功能等同于标准库cgi parse_qsl,但是是用C语言写的,速度更快。 转换一个query字符串,返回一个列表的数据,变量名和变量值对。 可选参数keep_blank_values和strict_parsing同上。 与上面函数的不同就是返回数据的格式。 redirect(req,location[,permanent=0,text=None]) 这是一个可以方便的重定向浏览器到另外一个地址的函数。当permanent为True时,MOVED_PERMANENTLY状态被发送到客户端,或者是MOVED_TEMPORARILY。并发送一段简短的文本告知浏览器,文档已经被移走(当这个罕见的浏览器不支持重定向时);提示文本可以被text参数覆盖。 如果这个函数在响应头已经被发送之后调用,会触发IOError异常。 这个函数触发apache.SERVER_RETURN异常放弃之后的处理。如果不想这样,可以在redirect之外套一个try/except块来捕捉异常。 4.7Cookie-HTTP状态管理 Cookie模块提供了方便的(convenient)的方法来创建,分析,发送和接收HTTP Cookies,按照Netscape的定义。 注意:尽管RFC工作组描述了如何使用Cookie,但是实际上还是只有Netscape原始浏览器支持。而且,很多流行的浏览器还是兼容IETF标准的,而且即便声称RFC兼容的。因此,这个模块支持当前范例,而不是完全RFC兼容的。 在特殊情况下,Netscape与RFC的Cookie有很大的区别,比如路径和域名。Cookie模块忽略这种引入的属性,所以所以所有引入的cookie以Netscape风格的cookie告终,没有属性的定义。 参考: 客户端持久化状态-HTTP Cookies http://wp.netscape.com/newref/std/cookie_spec.html RFC 2109,"HTTP状态管理机制" RFC 2964,"使用HTTP状态管理" RFC 2965,"HTTP状态管理机制" HTTP Cookies:标准,秘密与政见 http://arxiv.org/abs/cs.SE/0105018 4.7.1类定义 class Cookie(name,value[,attributes]) 这个类用于构造一个单一的cookie名为name,值为value。在Netscape和RFC2109中定义的属性将作为关键字参数。 属性描述了cookie的属性,而他们的字符串将会成为cookie的一部分。Cookie类限定了属性名必须是有效值,如下是可用的属性名:name、 value、version、path、domain、secure、comment、expires、max_age 、commentURL、discard、port、__data__。 __data__属性是一个通用的词典可用于存储任意值,如果需要。在使用Cookie的子集时很重要。 expires属性。按照如下格式解释'Wdy, DD-Mon-YYYY HH:MM:S GMT' (按照每个Netscape cookie的定义),或者按照新纪元开始的秒数(自动转换为GMT时间字符串)。无效的expires值会抛出ValueError异常。 当转换到字符串时,一个Cookie将会被转换到Cookie或Set-Cookie头。 注意:不像Python标准库Cookie类,这个类指定单一cookie,等同于Python标准库中的Morsel。 parse(string) 这是一个类方法,用于从一个cookie字符串创建Cookie实例并传递到响应头的值。转换过程中,属性名将会转换为小写。 因为这是个类方法,所以必须通过类来调用。 这个方法返回Cookie实例的词典,不是单一的Cookie实例。 如下是获取单一Cookie实例的示例: mycookies=Cookie.parse("spam=eggs; expires=Sat, \ 14-Jun-2003 02:42:36 GMT") spamcookie=mycookies["spam"] 注意:因为这个方法使用词典,所以不可能返回同名cookies。如果需要多个值在同一个cookie中,考虑使用MarshalCookie。 class SignedCookie(name,value,secret[,attributes]) 这是Cookie的子类。这个类按照name和value自动创建一个经过HMAC (md5)签名过的Cookie,secret必须是非空字符串。 parse(string,secret) 这个方法同Cookie.parse(),但是cookie要被验证。如果签名的验证失败,则返回Cookie类。 注意:通常检查SignedCookie.parse()的返回类型。如果返回类型是Cookie(而不是SignedCookie),则签名验证失败: #假设spam是一个签名过的cookie if type(spam) is not Cookie.SignedCookie: #签名验证失败的处理 class MarshalCookie(name,value,secret[,attributes]) 这是SignedCookie的子类。允许value是任何的集结(marshallable)对象。Python核心(core)类型如字符串,整数,列表等,都是集结类型对象。完整的列表查看marshal模块文档。 转换过程中会检查签名,不正确的签名的cookie无法被集结(unmarshalled)。 4.7.2函数 add_cookie(req,cookie[,value,attributes]) 向响应头方便的设置一个cookie。req是mod_python请求对象。如果cookie是一个Cookie类或其子类的实例。则cookie被设置,否则cookie参数必须是一个字符串,用于构造Cookie类的实例。cookie用作名字,value作为值,有效的Cookie属性作为关键字参数。 这个函数同时设置'Cache-Control: no-cache="set-cookie"'头来通知(inform)cookie值不需要缓存。 如下是使用这个函数的一种方法: c=Cookie.Cookie('spam','eggs',expires=time.time()+300) Cookie.add_cookie(req,c) 如下是另一个例子: Cookie.add_cookie(req,'spam','eggs',expires=time.time()+\ 300) get_cookies(req[,Class,data]) 从输入头获取(retrieving)cookie的方法。req是mod_python请求对象。Class是一个拥有parse()方法的用于转换成的cookie类,缺省是Cookie类。Data可以是任何关键字参数,将会被传递到parse()方法。对SignedCookie和MarshalCookie类等需要secret参数的parse()方法非常有用。 4.7.3例子 如下例子设置一个持续(expires)300秒的cookie: from mod_python import Cookie,apache import time def handler(req): cookie=Cookie.Cookie('eggs','spam') cookie.expires=time.time()+300 Cookie.add_cookie(req,cookie) req.write('此响应包含cookie!\n') return apache.OK 如下例子检查输入的集结cookie并显示到客户端。如果输入没有cookie则设置一个cookie。这个例子使用'secret007'作为HMAC签名。 from mod_python import apache,Cookie def handler(req): cookies=Cookie.get_cookies(req,Cookie.MarshalCookie,\ secret='secret007') if cookies.has_key('spam'): spamcookie=cookies['spam'] req.write('Great, a spam cookie was found: %s\n'\ % str(spamcookie)) if type(spamcookie) is Cookie.MarshalCookie: req.write('Here is what it looks like decoded'\ +':%s=%s\n'%(spamcookie.name,\ spamcookie.value)) else: req.write('WARNING: The cookie found is not a \ MarshalCookie, it may have been tapered\ with!') else: #MarshalCookie允许值为任何集结对象 value={'egg_count':32, 'color':'white'} Cookie.add_cookie(req,Cookie.MarshalCookie('spam',\ value,'secret007')) req.write('Spam cookie not found, but we just\ set one!\n') return apache.OK 4.8Session-对话管理 Session模块提供了跨越请求的持久化对象。 模块包含BaseSession类,但不可以直接使用。DbmSession类,使用dbm来存储对话。FileSession类,使用单独的文件存储对话。 BaseSession类也提供对话锁,支持进程和线程。锁定使用APR的global_mutexes函数。一定数量的锁在启动时预创建,互斥数用对话ID的hash()计算。因此就算两个对话具有不同的ID却有相同的哈希值,但仅有的联系(implication)是两个对话无法在同时被锁定。 4.8.1类 Session(req[,sid,secret,timeout,lock]) 此函数拥有与BaseSession相同的参数。 这个函数返回一个缺省的对话实例。对话类可被用于PythonOption session value,这里的value可以是DbmSession、MemorySession或FileSession。自定义的对话类暂时还不被支持。 如果PythonOption session没有找到,则函数查询MPM和基于它的返回一个DbmSession或MemorySession实例。 MemorySession类将被用于MPM支持线程,但是不支持fork的情况,比如Windows,或者用于支持线程,fork,但是只允许一个进程的情况,比如MPM可以配置成这种。在其他所有的情况,使用DbmSession。 class BaseSession(req[,sid,secret,timeout,lock]) 这个类意味着存储其他类并实现对话的存储机制。req是mod_python的请求对象的引用,是必须的。 BaseSession是dict类的子类。数据按照词典存取。 sid是一个可选的对话ID;如果提供则对话必须存在,忽略则会创建一个新的对话和新的sid。如果sid未提供,对象会在cookie中查找对话ID。如果找到了,但不是先前所指的,还会创建一个新的sid。判断是否是新创建的对话,调用is_new()方法。 Cookie有一个path属性用于比较DocumentRoot和目录在PythonHandler标志的作用中(病句,我自己也不懂)。比如,如果文档根目录是'/a/b/c',且PythonHandler指定为'/a/b/c/d/e',则路径会被设置为'/d/e'。也可以强制指定path使用ApplicationPath选项。即在服务器配置中的'PythonOption ApplicationPath /my/path选项。 当提供了secret参数时,BaseSession会使用SignedCookie来存储不可伪造(fake)的对话ID。缺省是简单的(plain)使用Cookie,假如没有被签名,则对话ID将会很难处理。 一个对话在超过timeout时间之后会失效而无法处理,缺省是30分钟。尝试装入期满(expired)的对话将会导致一个新的对话的产生。 lock参数缺省为1指定是否允许使用锁。当锁上时,只允许一个拥有相同对话ID的对话对象实例存在。 一个对话在刚创建时拥有"new"状态,而不通过cookie或sid参数来传递。 is_new() 如果返回1,则对话是刚刚创建的。在发生超时或不存在的sid时,也会新创建一个对话。使用这个方法来测试对话是否为新是很有用的: sess=Session(req) if sess.is_new(): #重定向到登录 util.redirect(req,'http://www.mysite.com/login') id() 返回对话ID created() 返回对话的创建时间,按照从新纪元(epoch)开始的秒数。 last_accessed() 返回上次存取时间,按照从新纪元开始的秒数。 timeout() 返回以秒为单位的超时间隔(timeout interval)。 set_timeout(secs) 设置超时时间为secs秒。 invalidate() 删除对话,并发送响应头要求删除客户端的对话相关cookie。 load() 从存储装入对话的值。 save() 将对话值写入存储。 delete() 从存储中删除对话。 init_lock() 初始化对话锁。无需每次都调用这个方法,仅在子类打算(intend)使用互斥锁(alternative lock)时使用。 lock() 锁住对话。如果对话已经被其他线程/进程锁住,则等待到锁被释放(release)时。锁是被自动控制的,而无需调用这个方法,缺省。这个方法也注册一个清理行为,在请求处理结束时解锁一个对话。 unlock() 解锁对话。同lock()当自动处理时(缺省),无需手工调用。 cleanup() 这个方法供子类实现对话的存储清理机制(比如删除超时对话等)。它将会被随机调用,调用的机会由CLEANUP_CHANGE变量,一个Session模块的成员来控制,缺省值为1000。这意味着被安排好(be ordered)的随机清理行为发生概率在1/1000的机会(chance)。子类实现这个方法之后,将不会按照时间强制的清理,但将会需要用req.register_cleanup注册清理行为来代替,执行请求之后的处理。 class DbmSession(req[,dbm,sid,secret,dbmtype,timeout,lock]) 这个类提供了使用dbm文件来存储对话的方法,dbm存储速度很快,且大多数dbm实现使用内存映射文件来提供更高的存取速度,其响应性能接近使用共享内存。 dbm是dbm文件名,且这个文件必须可被httpd进程写入。这个文件在服务器进程停止之后不会被删除,一个好处是服务器重启后对话仍然存在(survive)。缺省时对话信息保存在'mp_sess.dbm'文件中。也可在配置标志中指定路径PythonOption session_directory标志。路径和文件名可以在如下设置中重载PythonOption session_dbm filename。 当使用Python的anydbm模块实现时,在多数系统中缺省使用dbhash模块。如果需要特并的指定dbm的实现,如gdbm等,可以传递dbmtype参数。 注意这个类的使用不是跨平台的。具有最好的跨平台兼容性(compatibility)的,还是使用Session()来创建对话。 class FileSession(req[,sid,secret,timeout,lock, fast_cleanup,verify_cleanup]) 这是在版本3.2.0开始实现的。 此类在文件中存储对话数据,是BaseSession的子类。 对话数据存储在特定文件中。这些文件在服务器停止时不会被删除,所以对话可以在服务器重启之间继续有效。对话文件保存在由tempfile.gettempdir()标准库函数返回的临时目录下的mp_sess目录下。另一个可选路径是使用PythonOption session_directory /path/to/dir 来设置,并且这个目录必须存在且可用apache进程读写。 过期的对话文件将会被清理机制按周期(periodically)删除。清除行为受到fast_cleanup和verify_cleanup参数控制,也可以用PythonOption session_grace_period和PythonOption session_cleanup_time_limit来控制。
如果fast_cleanup为False,对话文件将会被非酸洗(unpickled?)并且超时(timeout)被用于决定对话是否要加入删除候选名单。fast_cleanup=Fasle意味着(imply)verify_cleanup=True。 超时(timeout)被用于计算请求的对话中哪些到达了超时,以用于调用filesession_cleanup。如果对话对象没有相同的超时,或者手动设定了特定(particular)对话的超时,需要设置verify_cleanup=True。 fast_cleanup的值也可以用PythonOption session_fast_cleanup来设置。
class MemorySession(req[,sid,secret,timeout,lock]) 这个类提供在全局词典中保存对话。提供更好的性能,但是需要多进程配置的支持,也会为每个对话耗费(consume)一定的内存。 注意使用这个类并不是跨平台的。为了跨平台,最好还是使用Session()函数来创建对话。 4.8.2例子 如下是记录点击次数的简单例子(demonstrate)。 from mod_python import Session def handler(req): session=Session.Session(req) try: session['hits']+=1 except: session['hits']=1 session.save() req.content_type='text/plain' req.write('Hits: %d\n' % session['hits']) return apache.OK 4.9psp-Python服务器端页面 psp模块提供一种从包含Python代码的文本(包含,但是不限于HTML文档),转换到适用于mod_python处理器的Python代码。提供一种类似于ASP,JSP等的动态内容嵌入技术。 psp的转换器使用C语言书写(使用flex),所以运行速度很快。 查看6.2节"PSP处理器"了解更多PSP的信息。 在文档内,Python代码需要被'和'%>'括起来。Python表达式需要附上(enclosed)'和'%>'。标志需要被'和'%>'括起来。作为代码一部分的注释需用'和'--%>'括起来。 如下是原始的PSP页面用于示例(demonstrate)同时包含代码和表达式的嵌入HTML文档的例子: import time %> Hello world, the time is: %H:%M:%S")%> 在内部,PSP转换器翻译如上页面到如下的Python代码: req.write(""" """) import time req.write(""" Hello world, the time is: """) req.write(str(time.strftime("%Y-%m-%d, %H:%M:%S"))) req.write(""" """) 这些代码将会在处理器的返回中显示:'Hello world, the time is: '加上当前时间。 Python代码可以被用于输出部分页面条件(conditionally)循环。代码将被显示成锯齿状。在下一段以锯齿括起的Python代码开始时,循环将被结束。哪怕这段代码只是一段注释。 如下是例子: for n in range(3): # this indent will persist %> This paragraph will be repeated 3 times. # this line will cause the block to end %> This line will only be shown once. 如下是内部自动生成的Python代码: req.write(""" """) for n in range(3): # this indent will persist req.write(""" This paragraph will be repeated 3 times. """) # this line will cause the block to end req.write(""" This line will only be shown onece. """) 转换器也会聪明的在以冒号结尾的Python代码后,识别新的''对来结束重置代码快,跳出循环。如下页面与如上的最终效果相同: for n in range(3): %> This paragraph will be repeated 3 times. %> This line will only be shown once. 无论如上代码如何混淆(confuse),这样用注释来结束代码块还是相当推荐的好习惯。 现在支持的唯一一个标志是include,如下用法: 函数parse()会被按照dir参数调用,并把文件转换到绝对路径。 class PSP(req[,filename,string,vars]) 这个类声明(represent)了一个PSP对象。 req是请求对象,filename和string是可选参数指定PSP源代码。但是只有一个会生效,如果没有指定则用req.filename来指定filename。 vars是一个全局变量词典。传递run()方法覆盖这里的vars参数。 这个类被PSP处理器在内部调用,但也可以被模板工具使用。 当使用文件作为源时,代码对象将会返回缓存中的文件对象和文件修改时间。缓存是作用于全局的Python解释器。所以除非文件修改时间改变了,文件无需重新编译和解释。 缓存限制到512个页面,依赖于可用内存总量。如果与内存有关,可以选择使用dbm文件缓存。作者简单的测试表明,使用bsd db之后大约性能慢了20%。也需要测试anydbm在你的平台上的缺省实现对大小的限制是否合适。dbm缓存允许通过PSPDbmCache这个PythonOption,例如: PythonOption PSPDbmCache ''/tmp/pspcache.dbm'' 注意,dbm缓存在服务器重启时是不会被删除的。 不像使用文件,从字符串来的代码对象只会缓存在内存中。无需选项来缓存dbm文件。 run([vars]) 这个方法将会执行代码(由对象初始化时转换和编译过的PSP代码)。可选参数vars是一个用于传送全局变量的词典。另外,PSP代码可以使用全局变量如req,psp,session和form。一个对话将被创建,并可以在PSP代码中使用session变量(PSP代码检查co_names代码对象来做决定)。记住在处理session和打开对话锁时会有一些阻塞。类似的,mod_python的FieldStorage对象将会实例化为form对象。PSPInstance类会传递psp对象作为实例。 display_code() 返回HTML格式的PSP原始代码。如下是PSP的模板机制: 模板文件: Hello, ! 处理器代码如下: from mod_python import apache,psp def handler(req): template=psp.PSP(req,filename='template.html') template.run({'what':'world'}) return apache.OK class PSPInstance() PSP代码中全局变量psp对象所属的类。对象由内部负责实例化,所以__init__接口是没有文档的。 set_error_page(filename) 设置一个psp页面来处理抛出的异常。如果用绝对路径,将会添加到文档根目录,或者被假设为文件与当前页面在同一路径下。错误页会收到一个附加的变量exception,是一个三元素元组,由sys.exc_info()返回。 apply_data(object[,**kw]) 这个方法调用可执行对象object,传递表单参数data作为关键字参数,并返回结果。 redirect(location[,permanent=0]) 这个方法重定向浏览器到位置location。如果permanent是True,则MOVED_PERMANENTLY将会发送(不同于MOVED_TEMPORARILY)到客户端。 注意:重定向仅可在任何数据发送到客户端之前调用,调用它的Python代码必须在整个页面的顶端调用。否则会发生IOError异常。 例子: # note that the ' psp.redirect('http://www.modpython.org') %> 另外,psp模块还提供如下函数: parse(filename[,dir]) 此函数打开文件filename,读取和转换后返回Python代码。 如果制定了dir参数,最终(ultimate)用于转换的文件名由dir和filename构成。并且include标志也会被指定为相关路径。注意这只是简单的串连,dir之后不会自动加入路径分隔符。 parsestring(string) 同上,只是转换字符串string中的psp代码到Python代码。 完成... |