Sustie

主页 所有文章 文章检索

Python标准库的简易HTTP服务器

Python 标准库有一个名为http.server的模块,提供了简易的 HTTP 服务器功能。下面的示例代码用这个模块启动了一个简单的 HTTP 服务器。这个服务器只支持 POST 方法,会打印 POST 请求的信息,并返回一个固定的字符串。

from http.server import BaseHTTPRequestHandler, HTTPServer


class MyHandler(BaseHTTPRequestHandler):

    def do_POST(self):
        print('method:', self.command)
        print('path:', self.path)
        print('HTTP version:', self.request_version)
        print('headers:', self.headers)
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length).decode()
        print('body:', body)

        response = b'Roger!'
        self.send_response(200)
        self.send_header('Content-Length', len(response))
        self.end_headers()
        self.wfile.write(response)


if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8080), MyHandler)
    server.serve_forever()

要测试这个服务器,可以发送一个简单的 POST 请求:

import requests

res = requests.post('http://localhost:8080/', data='Hello!')
print(res.text)

在服务端应该会看到类似下面的输出:

method: POST
path: /
HTTP version: HTTP/1.1
headers: Host: localhost:8080
User-Agent: python-requests/2.32.3
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 6


body: Hello!

而客户端则会收到如下的响应:

Roger!

下面对示例代码的关键部分进行更加详细地说明。

HTTP 服务器的具体逻辑是通过继承BaseHTTPRequestHandler基类来实现的。当 HTTP 服务器收到 GET 请求时,就会调用对象的do_GET()方法,收到 POST 请求时会调用对象的do_POST()方法,以此类推。

BaseHTTPRequestHandler基类提供了访问 HTTP 请求内容以及发送响应的接口。

HTTP 请求的 request line 可以通过commandpathrequest_version属性来获取,它们都是字符串。请求的头部信息可以通过headers属性获取。headers的类型是http.client.HTTPMessage,是一个类似于dict的对象。通过读取rfile,可以读取请求的 body 部分。

发送响应只需要往wfile中写入数据即可。发送 HTTP 响应的响应码和头部的时候,用send_response()send_header()方法会更加方便,这些方法的底层实现依然是往wfile中写入数据,真正写入数据是在调用end_headers()的时候。

http.server模块本身也提供了一个已经实现了的子类SimpleHTTPRequestHandler。通过在命令行输入python -m http.server 8080就可以快速启动一个使用了SimpleHTTPRequestHandler的 HTTP 服务器。