上一章讲SocketServer模块,它将服务端根据监听套接字和连接套接字分为了2个部分(BaseServer/BaseRequestHandler),而连接套接字类的处理方法相当简单,最终是一个handle函数就搞定了。http.server这个模块主要类BaseHTTPRequestHandle继承自BaseRequestHandle,对handle进行了一点点的加强,主要就是对http协议进行了简单的解析工作(源码版本Python3.5)

先上图为敬:D

这个模块只需要关心BaseHTTPRequestHandler类,其实里面还有个CGI处理类,不过这玩意儿估计也是上古神兽了。没关注的必要。

代码解读

  1. 支持http版本0.9、1.0、1.1,区别就是0.9版本只有body。1.1版本显式支持keep-alive。为了支持keep-alive,代码中有多处处理逻辑
  2. 对于内容的解析主要是使用parse_request方法。该方法逻辑主要解析第一行request line。如果出错就直接调用send_error返回错误内容。header部分主要引入了email.parser.Parser进行解析
  3. parser_request对Except:100-continue进行了特殊处理,见附录
  4. 返回status line和header是先使用send_response_only创建一个列表,然后调用send_header依次在列表中添加数据,最后调用end_headers发送数据
  5. send_error函数就是一个回复的典范
  6. 剩下就是日志函数和几个辅助函数了

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from http.server import BaseHTTPRequestHandler
from socketserver import ThreadingTCPServer


class Handle(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"

def do_GET(self):
self.send_error(500)

def do_POST(self):
len = self.headers.get('Content-Length')
data = self.rfile.read(int(len))

self.send_response(200)
self.send_header('Content-Length', len)
self.end_headers()
self.wfile.write(data)

ThreadingTCPServer(('', 9999), Handle).serve_forever()

这是一个最简的http server。do_GET函数表面send_error就能够响应一个请求。do_POST函数参照send_error的逻辑只不过读取了客户端发送的body字段

小知识

类变量和实例变量

这2个非常相近,具体区别我就不概述了。在写代码的时候很多人无脑self.xxx = xxx就搞了一个实例变量。大多数时候用实例变量都能够替代类变量的功能。这很容易让人忽略类变量的优点。①含义明确:这是这个类的所有实例共用的。②不需要重载__init__,这在继承的时候是很有用哒~~~,so,不要有事没事无脑在__init__里面self.xxx = xxx啦

相关资料

Expect:100-continue
官方文档