Skip to main content

21.22. http.server — HTTP服务器

源代码: Lib/http/server.py


此模块定义用于实现HTTP服务器(Web服务器)的类。

一个类,HTTPServer,是一个 socketserver.TCPServer 子类。它创建和侦听HTTP套接字,将请求分派给处理程序。创建和运行服务器的代码如下所示:

def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler):
    server_address = ('', 8000)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()
class http.server.HTTPServer(server_address, RequestHandlerClass)

此类基于 TCPServer 类构建,将服务器地址存储为名为 server_nameserver_port 的实例变量。服务器可由处理程序访问,通常通过处理程序的 server 实例变量。

HTTPServer 必须在实例化时给予 RequestHandlerClass,本模块提供三种不同的变体:

class http.server.BaseHTTPRequestHandler(request, client_address, server)

这个类用于处理到达服务器的HTTP请求。它本身不能响应任何实际的HTTP请求;它必须被子类化以处理每个请求方法(例如GET或POST)。 BaseHTTPRequestHandler 提供了许多类和实例变量,以及供子类使用的方法。

处理程序将解析请求和头,然后调用特定于请求类型的方法。方法名称由请求构造。例如,对于请求方法 SPAM,将调用没有参数的 do_SPAM() 方法。所有相关信息存储在处理程序的实例变量中。子类不应该需要覆盖或扩展 __init__() 方法。

BaseHTTPRequestHandler 有以下实例变量:

client_address

包含 (host, port) 形式的引用客户端地址的元组。

server

包含服务器实例。

close_connection

应在 handle_one_request() 返回之前设置的布尔值,指示是否可能需要另一个请求,或者是否应关闭连接。

requestline

包含HTTP请求行的字符串表示形式。终止CRLF被剥离。此属性应由 handle_one_request() 设置。如果没有处理有效的请求行,则应将其设置为空字符串。

command

包含命令(请求类型)。例如,'GET'

path

包含请求路径。

request_version

包含请求中的版本字符串。例如,'HTTP/1.0'

headers

保存由 MessageClass 类变量指定的类的实例。此实例解析和管理HTTP请求中的标头。来自 http.clientparse_headers() 函数用于解析头部,并且它要求HTTP请求提供有效的 RFC 2822 样式头部。

rfile

io.BufferedIOBase 输入流,准备从可选输入数据的开始读取。

wfile

包含用于将响应写回客户端的输出流。在写入此流时,必须正确遵守HTTP协议。

在 3.6 版更改: 这是一个 io.BufferedIOBase 流。

BaseHTTPRequestHandler 具有以下属性:

server_version

指定服务器软件版本。您可能想要覆盖此。格式是多个以空格分隔的字符串,其中每个字符串的格式名称为[/version]。例如,'BaseHTTP/0.2'

sys_version

包含Python系统版本,以 version_string 方法和 server_version 类变量可用的形式。例如,'Python/1.4'

error_message_format

指定 send_error() 方法应用于为客户端构建错误响应的格式字符串。默认情况下,字符串使用来自 responses 的变量填充,这些变量基于传递给 send_error() 的状态代码。

error_content_type

指定发送到客户端的错误响应的Content-Type HTTP头。默认值为 'text/html'

protocol_version

这指定在响应中使用的HTTP协议版本。如果设置为 'HTTP/1.1',服务器将允许HTTP持久连接;然而,您的服务器 must 然后在其对客户端的所有响应中包括精确的 Content-Length 头(使用 send_header())。为了向后兼容,设置默认为 'HTTP/1.0'

MessageClass

指定一个 email.message.Message -like类来解析HTTP头。通常,这不会被覆盖,它默认为 http.client.HTTPMessage

responses

此属性包含错误代码整数到包含短和长消息的两元素元组的映射。例如,{code: (shortmessage, longmessage)}shortmessage 通常在错误响应中用作 message 密钥,longmessage 用作 explain 密钥。它由 send_response_only()send_error() 方法使用。

BaseHTTPRequestHandler 实例具有以下方法:

handle()

调用 handle_one_request() 一次(或,如果持续连接启用,多次)以处理传入的HTTP请求。你应该永远不需要覆盖它;而是实施适当的 do_*() 方法。

handle_one_request()

此方法将解析并分派请求到适当的 do_*() 方法。你应该永远不需要重写它。

handle_expect_100()

当符合HTTP/1.1的服务器接收到 Expect: 100-continue 请求头时,它使用 100 Continue,然后是 200 OK 头来响应。如果服务器不希望客户端继续,则可以覆盖此方法以引发错误。例如,服务器可以选择发送 417 Expectation Failed 作为响应头和 return False

3.2 新版功能.

send_error(code, message=None, explain=None)

向客户端发送并记录完整的错误回复。数字 code 指定HTTP错误代码,以 message 作为错误的可选,简短,可读的描述。 explain 参数可用于提供有关错误的更详细信息;它将使用 error_message_format 属性格式化,并在一组完整的标题之后作为响应正文发出。 responses 属性保存将在没有提供值时使用的 messageexplain 的默认值;对于未知代码,两者的默认值为字符串 ???。如果方法是HEAD或响应代码是以下之一,则主体将为空:1xx204 No Content205 Reset Content304 Not Modified

在 3.4 版更改: 错误响应包括Content-Length头。添加了 explain 参数。

send_response(code, message=None)

向头缓冲区添加响应头,并记录接受的请求。 HTTP响应行写入内部缓冲区,然后是 ServerDate 头。这两个头的值分别从 version_string()date_time_string() 方法中选取。如果服务器不打算使用 send_header() 方法发送任何其他头部,则 send_response() 之后应该是 end_headers() 调用。

在 3.3 版更改: 标题存储到内部缓冲区,end_headers() 需要显式调用。

send_header(keyword, value)

将HTTP头添加到内部缓冲区,当调用 end_headers()flush_headers() 时,将写入输出流。 keyword 应该指定header关键字,用 value 指定它的值。注意,在send_header调用完成后,必须调用 end_headers() 以完成操作。

在 3.2 版更改: 标题存储在内部缓冲区中。

send_response_only(code, message=None)

仅发送响应头,用于当服务器将 100 Continue 响应发送到客户端时的目的。头缓冲并直接发送输出流。如果没有指定 message,则发送对应于响应 code 的HTTP消息。

3.2 新版功能.

end_headers()

在头缓冲区中添加一个空行(指示响应中HTTP头的结尾)并调用 flush_headers()

在 3.2 版更改: 缓冲的头部被写入输出流。

flush_headers()

最后发送头到输出流和刷新内部头缓冲区。

3.3 新版功能.

log_request(code='-', size='-')

记录接受(成功)请求。 code 应该指定与响应相关联的数字HTTP代码。如果响应的大小可用,则应将其作为 size 参数传递。

log_error(...)

在无法满足请求时记录错误。默认情况下,它将消息传递给 log_message(),因此它接受相同的参数(format 和附加值)。

log_message(format, ...)

将任意消息记录到 sys.stderr。这通常被覆盖以创建自定义错误日志记录机制。 format 参数是标准的printf样式格式字符串,其中 log_message() 的附加参数作为格式化的输入应用。客户端IP地址和当前日期和时间以每个记录的消息为前缀。

version_string()

返回服务器软件的版本字符串。这是 server_versionsys_version 属性的组合。

date_time_string(timestamp=None)

返回由 timestamp (必须是 Nonetime.time() 返回的格式)给出的为消息头格式化的日期和时间。如果省略 timestamp,则使用当前日期和时间。

结果看起来像 'Sun, 06 Nov 1994 08:49:37 GMT'

log_date_time_string()

返回当前日期和时间,格式为日志记录。

address_string()

返回客户端地址。

在 3.3 版更改: 以前,执行了名称查找。为了避免名称解析延迟,它现在总是返回IP地址。

class http.server.SimpleHTTPRequestHandler(request, client_address, server)

此类提供当前目录及其以下的文件,直接将目录结构映射到HTTP请求。

很多工作,如解析请求,由基类 BaseHTTPRequestHandler 完成。这个类实现了 do_GET()do_HEAD() 函数。

以下被定义为 SimpleHTTPRequestHandler 的类级属性:

server_version

这将是 "SimpleHTTP/" + __version__,其中 __version__ 在模块级别定义。

extensions_map

将后缀映射到MIME类型的字典。默认值由空字符串表示,并被认为是 application/octet-stream。映射使用大小写不敏感,因此应仅包含低位密钥。

SimpleHTTPRequestHandler 类定义以下方法:

do_HEAD()

这种方法服务于 'HEAD' 请求类型:它发送它将为等效 GET 请求发送的头部。有关可能的标题的更完整的解释,请参阅 do_GET() 方法。

do_GET()

通过将请求解释为相对于当前工作目录的路径,将请求映射到本地文件。

如果请求映射到目录,将检查目录中是否存在名为 index.htmlindex.htm 的文件(按此顺序)。如果找到,则返回文件的内容;否则通过调用 list_directory() 方法生成目录列表。此方法使用 os.listdir() 扫描目录,如果 listdir() 失败,则返回 404 错误响应。

如果请求映射到文件,则会打开它并返回内容。打开请求的文件中的任何 OSError 异常映射到 404'File not found' 错误。否则,通过调用 guess_type() 方法猜测内容类型,guess_type() 方法又使用 extensions_map 变量。

输出具有猜测的内容类型的 'Content-type:' 报头,随后是具有文件大小的 'Content-Length:' 报头和具有文件修改时间的 'Last-Modified:' 报头。

然后跟随一个空行,表示标题的结尾,然后输出文件的内容。如果文件的MIME类型以 text/ 开头,则文件以文本模式打开;否则使用二进制模式。

例如用法,参见 http.server 模块中 test() 函数调用的实现。

SimpleHTTPRequestHandler 类可以以下列方式使用,以便创建一个非常基本的web服务器来提供相对于当前目录的文件:

import http.server
import socketserver

PORT = 8000

Handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print("serving at port", PORT)
    httpd.serve_forever()

http.server 也可以使用带有 port number 参数的解释器的 -m 开关直接调用。与上一个示例类似,此文件相对于当前目录提供文件:

python -m http.server 8000

默认情况下,服务器将自身绑定到所有接口。选项 -b/--bind 指定其应绑定的特定地址。例如,以下命令使服务器仅绑定到localhost:

python -m http.server 8000 --bind 127.0.0.1

3.4 新版功能: 引入了 --bind 参数。

class http.server.CGIHTTPRequestHandler(request, client_address, server)

这个类用于从当前目录及下面的文件或CGI脚本的输出。注意,将HTTP分层结构映射到本地目录结构与 SimpleHTTPRequestHandler 中的完全一样。

注解

CGIHTTPRequestHandler 类运行的CGI脚本不能执行重定向(HTTP代码302),因为在执行CGI脚本之前发送代码200(随后的脚本输出)。这会优先处理状态代码。

然而,类将运行CGI脚本,而不是将其作为文件,如果它猜测它是一个CGI脚本。仅使用基于目录的CGI —其他常见的服务器配置是将特殊扩展视为表示CGI脚本。

do_GET()do_HEAD() 功能被修改为运行CGI脚本并提供输出,而不是服务文件,如果请求导致 cgi_directories 路径下面的某处。

CGIHTTPRequestHandler 定义以下数据成员:

cgi_directories

此默认值为 ['/cgi-bin', '/htbin'],并描述要视为包含CGI脚本的目录。

CGIHTTPRequestHandler 定义以下方法:

do_POST()

此方法提供 'POST' 请求类型,仅允许用于CGI脚本。错误501,“只能向CGI脚本发布”,当尝试POST到非CGI URL时输出。

注意,出于安全原因,CGI脚本将以用户nobody的UID运行。 CGI脚本的问题将被转换为错误403。

可以通过传递 --cgi 选项在命令行中启用 CGIHTTPRequestHandler:

python -m http.server --cgi 8000