一个简单的 Python Http 服务器
#!/usr/bin/env python
# encoding: utf-8
import BaseHTTPServer
def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
run()
这就是一个非常简单地 http 服务器了,将这段代码保存为 server.py,然后使用
python server.py
运行起来,在浏览器中输入:
http://localhost:8000
之后,你应该看到的是:
Error response
Error code 501.
Message: Unsupported method ('GET').
Error code explanation: 501 = Server does not support this operation.
这段错误的提示。
我们仔细得看一下这段提示,可以发现原来是服务器不支持 GET 方法。OK,我们直接输入网址默认使用的就是 GET,那既然提示的是 501,那么就说明这个 URL 是有效地,但是方法不被支持。
秉着求知的态度我们来看一下 HTTPServer 的文档。
打开文档网址:
https://docs.python.org/2/library/basehttpserver.html
我们通过阅读文档可以发现:
HttpServer 本身不处理请求,它仅用于接收请求,真正的处理逻辑是由 HttpRequestHandler 进行的。但事实上,HttpRequestHandler 是不能响应任何 http 请求的,必须使用继承子类的方式去实现对应 http 请求方法的响应(GET/POST)。HttpRequestHandler 提供了大量类变量,实例变量以及方法给子类使用。
okay,既然如此,那我们就来看看 HttpRequestHandler 有哪些方法是可以给子类使用的。
扫了一遍文档,我发现了这两个函数,他的表述是这样的:
handle()
调用一次 handle_one_request() 去处理进来的 http 请求(如果是持久连接的话,将会调用多次),你绝对不要试图重写这个函数,而是应该实现各种 do_* 方法。
handle_one_request()
这个函数将会解析并且将请求分发给对应的 do_* 方法,你真的不需要重写这个函数。
好,很好,非常好,感觉有点头绪了,那文档都这样说了,我们就看看人家的代码是怎么实现的,我本地的环境是 python 2.7.10,所以看得是 2.7.10 的源码:
首先是 handle 的源码:
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = 1
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
很好,正如文档里面所说,真的就调用了 handle_one_request 函数,那咱就继续看 handle_one_request 函数的源码:
def handle_one_request(self):
try:
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(414)
return
if not self.raw_requestline:
self.close_connection = 1
return
if not self.parse_request():
# An error code has been sent, just exit
return
mname = 'do_' + self.command
if not hasattr(self, mname):
self.send_error(501, "Unsupported method (%r)" % self.command)
return
method = getattr(self, mname)
method()
self.wfile.flush() #actually send the response if not already done.
except socket.timeout, e:
#a read or a write timed out. Discard this connection
self.log_error("Request timed out: %r", e)
self.close_connection = 1
return
也和文档说的一致,解析参数,然后查找 do_* 方法,查找到之后调用了,然后就这样了。
在阅读完文档以及简单得跟踪了一下代码之后,我们就修改一下开头的服务器,使它能够返回一些内容,这里就假设为最简单的 "Hello Python"为例,可以改写成这样:
#!/usr/bin/env python
# encoding: utf-8
import BaseHTTPServer
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write('Hello Python')
def run(server_class=BaseHTTPServer.HTTPServer,
handler_class=MyHandler):
server_address = ('', 8000)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
run()
这下再启动起来,再浏览器上访问:
http://localhost:8000
你应该就可以看到 Hello Python 了。