python simplehttp_Python SimpleHTTPServer.py 源码分析

前面分析BaseServer和BaseHTTPServer,可以知道BaseHTTPRequestHandler中handle_one_request方法将会通过自省的方式,调用HTTP客户端请求的方法。

def handle_one_request(self):

try:

# 省略... ...

method = getattr(self, mname)

method()

self.wfile.flush() #actually send the response if not already done.

except socket.timeout, e:

# 省略... ...

显然method将会在BaseHTTPRequestHandler的子类中实现。我们已经知道,但凡以Base开头的class,都需要被继承,然后在其子类中实现相关的方法。

SimpleHTTPServer

构建一个简单的HTTP服务,需要继承HTTPServer,同时requesthandler也需要继承BaseHTTPRequestHandler。python已经实现了一个例子,那就是SimpleHTTPServer。因此分析SimpleHTTPServer来查看如何使用前面的一些类构建http服务。

曾经为了表示python的简洁优雅,经常会举这样的例子,python可以一行代码开启一个服务器。

$ python -m SimpleHTTPServer

这里的SimpleHTTPServer就是实现了HTTPServer的模块。

SimpleHTTPServer通过调用BaseHTTPServer模块的test方法做为入口。

def test(HandlerClass = SimpleHTTPRequestHandler,

ServerClass = BaseHTTPServer.HTTPServer):

BaseHTTPServer.test(HandlerClass, ServerClass)

test方法做了两件事,第一件就是使用HTTPServer接受一个监听地址和requestClass参数,创建了一个实例对象,调用server_forever方法开启服务。

SimpleHTTPRequestHandler

根据之前的分析,使用httpserver的服务,我们只需要继续BaseHTTPRequestHandler,并提供自省的method方法即可。

class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

server_version = "SimpleHTTP/" + __version__

def do_GET(self):

f = self.send_head()

if f:

self.copyfile(f, self.wfile)

f.close()

def do_HEAD(self):

f = self.send_head()

if f:

f.close()

do_GET 和 do_HEAD 分别实现了http的get请求和head请求的处理。他们调用send_head方法:

def send_head(self):

path = self.translate_path(self.path)

f = None

if os.path.isdir(path):

if not self.path.endswith('/'):

self.send_response(301)

self.send_header("Location", self.path + "/")

self.end_headers()

return None

for index in "index.html", "index.htm":

index = os.path.join(path, index)

if os.path.exists(index):

path = index

break

else:

return self.list_directory(path)

ctype = self.guess_type(path)

try:

f = open(path, 'rb')

except IOError:

self.send_error(404, "File not found")

return None

self.send_response(200)

self.send_header("Content-type", ctype)

fs = os.fstat(f.fileno())

self.send_header("Content-Length", str(fs[6]))

self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))

self.end_headers()

return f

send_head 方法通过uri的path分析得到客户请求的网路路径。构造head的mime元信息并发送到客户端,然后返回一个打开path的文件句柄。

copyfile

do_GET的下一步就是通过 copyfile方法,将客户请求的path的文件数据写入到缓冲可写文件中,发送给客户端。

list_directory

SimpleHTTPServer模块还提供了list_directory方法,用于响应path是一个目录,而不是文件的情况。

def list_directory(self, path):

try:

list = os.listdir(path)

except os.error:

self.send_error(404, "No permission to list directory")

return None

list.sort(key=lambda a: a.lower())

f = StringIO()

displaypath = cgi.escape(urllib.unquote(self.path))

f.write('')

f.write("\n

Directory listing for %s\n" % displaypath)

f.write("

\n

Directory listing for %s

\n" % displaypath)

f.write("


\n
  • \n")

for name in list:

fullname = os.path.join(path, name)

displayname = linkname = name

# Append / for directories or @ for symbolic links

if os.path.isdir(fullname):

displayname = name + "/"

linkname = name + "/"

if os.path.islink(fullname):

displayname = name + "@"

# Note: a link to a directory displays with @ and links with /

f.write('

%s\n'

% (urllib.quote(linkname), cgi.escape(displayname)))

f.write("

\n
\n\n\n")

length = f.tell()

f.seek(0)

self.send_response(200)

encoding = sys.getfilesystemencoding()

self.send_header("Content-type", "text/html; charset=%s" % encoding)

self.send_header("Content-Length", str(length))

self.end_headers()

return f

由此可见,处理客户端的请求,只需要使用 send_reponse, send_header 和 end_headers ,就能向客户端发送reponse。

自定义http服务

定义一个CustomHTTPRequestHadnler继承自BaseHTTPRequestHandler。在其内实现do_GET 方法来处理get请求。

然后再定义一个CustomHTTPServer继承自HTTPServer,它接受CustomHTTPRequestHadnler作为自己的handler。简单的代码如下:

# -*- coding: utf-8 -*-

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer

class CustomHTTPRequestHandler(BaseHTTPRequestHandler):

def do_GET(self):

self.send_response(200)

self.send_header('Content-type', 'text/html')

self.end_headers()

self.wfile.write("hello world\r\n")

class CustomHTTPServer(HTTPServer):

def __init__(self, host, port):

HTTPServer.__init__(self, (host, port), CustomHTTPRequestHandler)

def main():

server = CustomHTTPServer('127.0.0.1', 8000)

server.serve_forever()

if __name__ == '__main__':

main()

使用curl访问可以得到

➜ ~ curl http://127.0.0.1:8000

hello world

➜ ~

控制台会打出访问的log。

127.0.0.1 - - [01/Jun/2015 11:42:33] "GET / HTTP/1.1" 200 -

从socket的建立,select的IO模式,再到Server和Handler的组合构建服务。我们已经熟悉了python的基本网络编程。python的web开发中,更多是使用WSGI协议。实现该协议的还有 uWSGI和gunicorn等库。相比那些库,python内部提供了一个wsgiref模块,实现了一个简单wsgi服务--simple_server。

接下来将会通过分析simple_server,更好的掌握WSGI协议。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值