21.22. http.server — HTTP 服务器

源代码: Lib/http/server.py


这个模块定义了实现 HTTP 服务器( Web 服务器)的类。

警告

http.server is not recommended for production. It only implements only basic security checks.

HTTPServersocketserver.TCPServer 的一个子类。它会创建和侦听 HTTP 套接字,并将请求调度给处理程序。用于创建和运行服务器的代码看起来像这样:

  1. def run(server_class=HTTPServer, handler_class=BaseHTTPRequestHandler):
  2. server_address = ('', 8000)
  3. httpd = server_class(server_address, handler_class)
  4. httpd.serve_forever()

class http.server.HTTPServer(server_address, RequestHandlerClass)

该类基于 TCPServer 类,并会将服务器地址存入名为 server_nameserver_port 的实例变量中。服务器可被处理程序通过 server 实例变量访问。

The HTTPServer 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() 方法。 所有相关信息会被保存在该处理程序的实际变量中。 子类不需要重载或扩展 __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.client 中的 parse_headers() 函数将被用来解析标头并且它需要 HTTP 请求提供一个有效的 RFC 2822 风格的标头。

  • rfile

    一个 io.BufferedIOBase 输入流,准备从可选的输入数据的开头进行读取。

  • wfile

    包含用于写入响应并发回给客户端的输出流。 在写入流时必须正确遵守 HTTP 协议以便成功地实现与 HTTP 客户端的互操作。

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

BaseHTTPRequestHandler 具有下列属性:

  • server_version

    指定服务器软件版本。 你可能会想要重载该属性。 该属性的格式为多个以空格分隔的字符串,其中每个字符串的形式为 name[/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 永久连接;但是,这样你的服务器 必须 在发给客户端的所有响应中包括一个准确的 Content-Length 标头 (使用 send_header())。 为了向下兼容,该设置默认为 'HTTP/1.0'

  • MessageClass

    指定一个 email.message.Message 这样的类来解析 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()

    When a HTTP/1.1 compliant server receives an Expect: 100-continue request header it responds back with a 100 Continue followed by 200 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 send 417 Expectation Failed as a response header and return False.

    3.2 新版功能.

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

    发送并记录回复给客户端的完整错误信息。 数字形式的 code 指明 HTTP 错误代码,可选的 message 为简短的易于人类阅读的错误描述。 explain 参数可被用于提供更详细的错误信息;它将使用 error_message_format 属性来进行格式化并在一组完整的标头之后作为响应体被发送。 responses 属性存放了 messageexplain 的默认值,它们将在未提供时被使用;对于未知代码两者的默认值均为字符串 ???。 如果方法为 HEAD 或响应代码是下列值之一则响应体将为空: 1xx, 204 No Content, 205 Reset Content, 304 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 应当指定标头关键字,并以 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 所给定的日期和时间(参数应为 None 或为 time.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

    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() 方法。

  • do_GET()

    这一请求通过把其解释为当前工作目录的相对路径来映射到本地文件

    如果请求被映射到目录,则会依次检查该目录是否存在 index.htmlindex.htm 文件。若存在则返回文件内容;否则会调用 list_directory() 方法生成目录列表。本方法将利用 os.listdir() 扫描目录,如果 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 the guess_type() method, which in turn uses the extensions_map variable.

    将会输出 'Content-type:' 头部信息,带上猜出的内容类型,然后是 'Content-Length:' 头部信息,带有文件的大小,以及 'Last-Modified:' 头部信息,带有文件的修改时间。

    后面是一个空行,标志着头部信息的结束,然后输出文件的内容。如果文件的 MIME 类型以 text/ 开头,文件将以文本模式打开;否则将使用二进制模式。

    用法示例请参阅 http.server 模块中的 test() 函数的实现。

SimpleHTTPRequestHandler 类的用法可如下所示,以便创建一个非常简单的 Web 服务,为相对于当前目录的文件提供服务:

  1. import http.server
  2. import socketserver
  3. PORT = 8000
  4. Handler = http.server.SimpleHTTPRequestHandler
  5. with socketserver.TCPServer(("", PORT), Handler) as httpd:
  6. print("serving at port", PORT)
  7. httpd.serve_forever()

http.server 也可使用解释器的 -m 开关加上 port number 参数直接发起调用。 与前面的例子类似,可支持相对于当前目录的文件:

  1. python -m http.server 8000

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:

  1. 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 脚本是通过特殊的扩展名。

如果请求指向 cgi_directories 以下的路径,do_GET()do_HEAD() 函数已作修改,不是给出文件,而是运行 CGI 脚本并输出结果。

CGIHTTPRequestHandler 定义了以下数据成员:

  • cgi_directories

    默认为 ['/cgi-bin', '/htbin'],视作 CGI 脚本所在目录。

CGIHTTPRequestHandler 定义了以下方法:

  • do_POST()

    本方法服务于 'POST' 请求,仅用于 CGI 脚本。如果试图向非 CGI 网址发送 POST 请求,则会输出错误 501:Can only POST to CGI scripts”。

请注意,为了保证安全性,CGI 脚本将以用户 nobody 的 UID 运行。CGI 脚本运行错误将被转换为错误 403。

通过在命令行传入 --cgi 参数,可以启用 CGIHTTPRequestHandler

  1. python -m http.server --cgi 8000