平平无奇,看过SocketServer之后,只要了解HTTP协议就能看明白。
HTTPServer 继承自 SocketServer.TCPServer;
BaseHTTPRequestHandler 继承自 SocketServer.StreamRequestHandler。
HTTP协议本身就是在TCP之上建立的应用层协议,所以不需要做太多的工作。这里的事项方法是将协议的解析等工作放到Handler类中,在Server类中仅仅覆盖了server_bind函数:
1. 首先调用TCPServer.server_bind;
2. 然后通过 socket. socket.getsockname 和 socket.getfqdn得到完整的主机名和端口。
HTTP请求数据流中的三个部分:
1. 第一行表示“请求的类型”和“路径”,格式为 <command> <path> [<version>];
2. 可选的HEADERS;HEADER之间用CRLF或LF分割;
3. 可选的数据部分;数据和HEADER之间由一个空行分割。
HTTP相应数据流中的三个部分:
1. 第一行表示响应代码,格式为 <version> <response_code> [<responsestring>];
2. 可选的HEADERS;
3. 数据部分;和HEADER之间由一个空行分割。
在SocketServer.BaseRequestHandler的构造函数中,调用了三个方法:setup, handle, finish。其中handler用来处理请求,而且被实现为空函数。
在 SocketServer.StreamRequestHandler中,并没有对handle进行覆盖,而是覆盖setup将socket构造为输入和输出文件 rfile 和 wfile。
所以在BaseHTTPRequestHandler中,只需要覆盖handle,对客户端的请求进行处理。
self.close_connection = 1
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
这里的关键是close_connection。主要是为了区分http request header中的 keep-alive。
从rfile中读出一行;这一行就是command + path行;
如果读取成功,调用parse_request解析客户端的请求;将请求的操作保存在self.command;判断类是否具有do_command(如do_POST)方法,如果没有,发送501错误;如果有则使用getattr魔法得到方法并调用。
解析从rfile中得到的那个command + path,没什么难度。
需要注意的是如果解析成功的话,会调用mimetools.Message的构造函数,生成一个类实例。这个构造函数需要rfile作为参数。构造过程其实也就是HEADERS的解析过程。
要具体研究一下这个类。
send_response,用来发送HTTP响应的第一行;
send_header,发送一个HEADER;
end_headers,发送一个空白行;
以及log函数和其它辅助函数。
有了TCPServer和StreamRequestHandler两个构造的非常好的基类,处理简单的HTTP请求并做出响应并不是难事。