21.22. http.server — HTTP 服务器
这个模块定义了实现 HTTP 服务器( Web 服务器)的类。
警告
is not recommended for production. It only implements only basic security checks.
HTTPServer 是 的一个子类。它会创建和侦听 HTTP 套接字,并将请求调度给处理程序。用于创建和运行服务器的代码看起来像这样:
class (server_address, RequestHandlerClass)
该类基于 TCPServer 类,并会将服务器地址存入名为 server_name
和 server_port
的实例变量中。服务器可被处理程序通过 server
实例变量访问。
The must be given a RequestHandlerClass on instantiation, of which this module provides three different variants:
class http.server.BaseHTTPRequestHandler
(request, client_address, server)
这个类用于处理到达服务器的 HTTP 请求。 它本身无法响应任何实际的 HTTP 请求;它必须被子类化以处理每个请求方法(例如 GET 或 POST)。 BaseHTTPRequestHandler 提供了许多供子类使用的类和实例变量以及方法。
这个处理程序将解析请求和标头,然后调用特定请求类型对应的方法。 方法名称将根据请求来构造。 例如,对于请求方法 SPAM
,将不带参数地调用 do_SPAM()
方法。 所有相关信息会被保存在该处理程序的实际变量中。 子类不需要重载或扩展 方法。
BaseHTTPRequestHandler 具有下列实例变量:
client_address
包含
(host, port)
形式的指向客户端地址的元组。server
包含服务器实例。
close_connection
应当在 返回之前设定的布尔值,指明是否要期待另一个请求,还是应当关闭连接。
requestline
包含 HTTP 请求行的字符串表示。 末尾的 CRLF 会被去除。 该属性应当由 handle_one_request() 来设定。 如果无有效请求行被处理,则它应当被设为空字符串。
command
包含具体的命令(请求类型)。 例如
'GET'
。path
包含请求路径。
request_version
包含请求的版本字符串。 例如
'HTTP/1.0'
。headers
存放由 类变量所指定的类的实例。 该实例会解析并管理 HTTP 请求中的标头。 http.client 中的
parse_headers()
函数将被用来解析标头并且它需要 HTTP 请求提供一个有效的 风格的标头。rfile
一个 io.BufferedIOBase 输入流,准备从可选的输入数据的开头进行读取。
wfile
包含用于写入响应并发回给客户端的输出流。 在写入流时必须正确遵守 HTTP 协议以便成功地实现与 HTTP 客户端的互操作。
在 3.6 版更改: 这是一个 流。
BaseHTTPRequestHandler 具有下列属性:
server_version
指定服务器软件版本。 你可能会想要重载该属性。 该属性的格式为多个以空格分隔的字符串,其中每个字符串的形式为 name[/version]。 例如
'BaseHTTP/0.2'
。sys_version
包含 Python 系统版本,采用 方法和 server_version 类变量所支持的形式。 例如
'Python/1.4'
。error_content_type
指定发送给客户端的错误响应的 Content-Type HTTP 标头。 默认值为
'text/html'
。-
该属性指定在响应中使用的 HTTP 协议版本。 如果设为
'HTTP/1.1'
,服务器将允许 HTTP 永久连接;但是,这样你的服务器 必须 在发给客户端的所有响应中包括一个准确的Content-Length
标头 (使用 )。 为了向下兼容,该设置默认为'HTTP/1.0'
。 MessageClass
指定一个 email.message.Message 这样的类来解析 HTTP 标头。 通常该属性不会被重载,其默认值为 。
responses
该属性包含一个整数错误代码与由短消息和长消息组成的二元组的映射。 例如,
{code: (shortmessage, longmessage)}
。 shortmessage 通常是作为消息响应中的 message 键,而 longmessage 则是作为 explain 键。 该属性会被 和 send_error() 方法所使用。
实例具有下列方法:
handle
()调用 handle_one_request() 一次(或者如果启用了永久连接则为多次)来处理传入的 HTTP 请求。 你应该完全不需要重载它;而是要实现适当的
do_*()
方法。handle_one_request
()此方法将解析并将请求分配给适当的
do_*()
方法。 你应该完全不需要重载它。handle_expect_100
()When a HTTP/1.1 compliant server receives an
Expect: 100-continue
request header it responds back with a100 Continue
followed by200 OK
headers. This method can be overridden to raise an error if the server does not want the client to continue. For e.g. server can chose to send417 Expectation Failed
as a response header andreturn False
.3.2 新版功能.
send_error
(code, message=None, explain=None)发送并记录回复给客户端的完整错误信息。 数字形式的 code 指明 HTTP 错误代码,可选的 message 为简短的易于人类阅读的错误描述。 explain 参数可被用于提供更详细的错误信息;它将使用 属性来进行格式化并在一组完整的标头之后作为响应体被发送。 responses 属性存放了 message 和 explain 的默认值,它们将在未提供时被使用;对于未知代码两者的默认值均为字符串
???
。 如果方法为 HEAD 或响应代码是下列值之一则响应体将为空:1xx
,204 No Content
,205 Reset Content
,304 Not Modified
。在 3.4 版更改: 错误响应包括一个 Content-Length 标头。 增加了 explain 参数。
send_response
(code, message=None)将一个响应标头添加到标头缓冲区并记录被接受的请求。 HTTP 响应行会被写入到内部缓冲区,后面是 Server 和 Date 标头。 这两个标头的值将分别通过 和 date_time_string() 方法获取。 如果服务器不打算使用 方法发送任何其他标头,则 send_response() 后面应该跟一个 调用。
在 3.3 版更改: 标头会被存储到内部缓冲区并且需要显式地调用 end_headers()。
send_header
(keyword, value)将 HTTP 标头添加到内部缓冲区,它将在 或 flush_headers() 被发起调用时写入输出流。 keyword 应当指定标头关键字,并以 value 指定其值。 请注意,在 send_header 调用结束之后,必须调用 以便完成操作。
在 3.2 版更改: 标头将被存入内部缓冲区。
send_response_only
(code, message=None)只发送响应标头,用于当
100 Continue
响应被服务器发送给客户端的场合。 标头不会被缓冲而是直接发送到输出流。 如果未指定 message,则会发送与响应 code 相对应的 HTTP 消息。3.2 新版功能.
end_headers
()将一个空行(指明响应中 HTTP 标头的结束)添加到标头缓冲区并调用 flush_headers()。
在 3.2 版更改: 已缓冲的标头会被写入到输出流。
log_request
(code=’-‘, size=’-‘)记录一次被接受(成功)的请求。 code 应当指定与请求相关联的 HTTP 代码。 如果请求的大小可用,则它应当作为 size 形参传入。
log_error
(…)当请求无法完成时记录一次错误。 默认情况下,它会将消息传给 ,因此它接受同样的参数 (format 和一些额外的值)。
log_message
(format, …)将任意一条消息记录到
sys.stderr
。 此方法通常会被重载以创建自定义的错误日志记录机制。 format 参数是标准 printf 风格的格式字符串,其中会将传给 log_message() 的额外参数用作格式化操作的输入。 每条消息日志记录的开头都会加上客户端 IP 地址和当前日期时间。version_string
()返回服务器软件的版本字符串。 该值为 与 sys_version 属性的组合。
date_time_string
(timestamp=None)返回由 timestamp 所给定的日期和时间(参数应为
None
或为 所返回的格式),格式化为一个消息标头。 如果省略 timestamp,则会使用当前日期和时间。()
返回当前的日期和时间,为日志格式化
address_string
()返回客户端的地址
在 3.3 版更改: 在之前版本中,会执行一次名称查找。 为了避免名称解析的时延,现在将总是返回 IP 地址。
class http.server.SimpleHTTPRequestHandler
(request, client_address, server)
这个类为当前目录及以下的文件提供服务,直接映射目录结构到HTTP请求
诸如解析请求之类的大量工作都是由基类 BaseHTTPRequestHandler 完成的。本类实现了 和 do_HEAD() 函数。
以下是 的类属性。
server_version
这会是
"SimpleHTTP/" + __version__
,其中__version__
定义于模块级别。extensions_map
A dictionary mapping suffixes into MIME types. The default is signified by an empty string, and is considered to be
application/octet-stream
. The mapping is used case-insensitively, and so should contain only lower-cased keys.
SimpleHTTPRequestHandler 类定义了以下方法:
do_HEAD
()本方法为
'HEAD'
请求提供服务:它将发送等同于GET
请求的头文件。关于合法头部信息的更完整解释,请参阅 方法。do_GET
()这一请求通过把其解释为当前工作目录的相对路径来映射到本地文件
如果请求被映射到目录,则会依次检查该目录是否存在
index.html
或index.htm
文件。若存在则返回文件内容;否则会调用list_directory()
方法生成目录列表。本方法将利用 os.listdir() 扫描目录,如果 失败,则返回404
出错应答。If the request was mapped to a file, it is opened and the contents are returned. Any OSError exception in opening the requested file is mapped to a
404
,'File not found'
error. Otherwise, the content type is guessed by calling theguess_type()
method, which in turn uses the extensions_map variable.将会输出
'Content-type:'
头部信息,带上猜出的内容类型,然后是'Content-Length:'
头部信息,带有文件的大小,以及'Last-Modified:'
头部信息,带有文件的修改时间。后面是一个空行,标志着头部信息的结束,然后输出文件的内容。如果文件的 MIME 类型以
text/
开头,文件将以文本模式打开;否则将使用二进制模式。用法示例请参阅 模块中的 test() 函数的实现。
类的用法可如下所示,以便创建一个非常简单的 Web 服务,为相对于当前目录的文件提供服务:
http.server 也可使用解释器的 开关加上 port number
参数直接发起调用。 与前面的例子类似,可支持相对于当前目录的文件:
By default, server binds itself to all interfaces. The option -b/--bind
specifies a specific address to which it should bind. For example, the following command causes the server to bind to localhost only:
3.4 新版功能: 引入了 --bind
参数。
class http.server.CGIHTTPRequestHandler
(request, client_address, server)
该类可为当前及以下目录中的文件或输出 CGI 脚本提供服务。注意,把 HTTP 分层结构映射到本地目录结构,这与 SimpleHTTPRequestHandler 完全一样。
注解
由 类运行的 CGI 脚本不能进行重定向操作(HTTP 代码302),因为在执行 CGI 脚本之前会发送代码 200(接下来就输出脚本)。这样状态码就冲突了。
然而,如果这个类猜测它是一个 CGI 脚本,那么就会运行该 CGI 脚本,而不是作为文件提供出去。 只会识别基于目录的 CGI —— 另有一种常用的服务器设置,即标识 CGI 脚本是通过特殊的扩展名。
如果请求指向 cgi_directories
以下的路径,do_GET()
和 do_HEAD()
函数已作修改,不是给出文件,而是运行 CGI 脚本并输出结果。
CGIHTTPRequestHandler 定义了以下数据成员:
cgi_directories
默认为
['/cgi-bin', '/htbin']
,视作 CGI 脚本所在目录。
定义了以下方法:
请注意,为了保证安全性,CGI 脚本将以用户 nobody 的 UID 运行。CGI 脚本运行错误将被转换为错误 403。
通过在命令行传入 --cgi
参数,可以启用 CGIHTTPRequestHandler :