python BaseHTTPServer模块
BaseHTTPServer类是在SocketServer的基础上创建出的一个简单的HTTP servers应用类,而通过BaseHTTPRequestHandler方法我们可以直接实现GET、POST等请求。由于其只是一个简单的SocketServer.TCPServer子类,它本身并不支持多线程或多进程,如果想使用多线程或多进程,需要结合threading模块去fork,这在后面也会提到。
一、HTTP GET请求
代码如下:
1from BaseHTTPServer import BaseHTTPRequestHandler
2import urlparse
3class GetHandler(BaseHTTPRequestHandler):
4 def do_GET(self):
5 parsed_path = urlparse.urlparse(self.path)
6 message_parts = [
7 'CLIENT VALUES:',
8 'client_address=%s (%s)' % (self.client_address,
9 self.address_string()),
10 'command=%s' % self.command,
11 'path=%s' % self.path,
12 'real path=%s' % parsed_path.path,
13 'query=%s' % parsed_path.query,
14 'request_version=%s' % self.request_version,
15 '',
16 'SERVER VALUES:',
17 'server_version=%s' % self.server_version,
18 'sys_version=%s' % self.sys_version,
19 'protocol_version=%s' % self.protocol_version,
20 '',
21 'HEADERS RECEIVED:',
22 ]
23 for name, value in sorted(self.headers.items()):
24 message_parts.append('%s=%s' % (name, value.rstrip()))
25 message_parts.append('')
26 message = '\r\n'.join(message_parts)
27 self.send_response(200)
28 self.end_headers()
29 self.wfile.write(message)
30 return
31if __name__ == '__main__':
32 from BaseHTTPServer import HTTPServer
33 server = HTTPServer(('localhost', 8080), GetHandler)
34 print 'Starting server, use <ctrl-c> to stop'
35 server.serve_forever()</ctrl-c>
其中wfile方法用于向客户端返回信息,send_response返回对应的http代码。上面的监听地址可以跟据自已的需求进行修改。当我们运行以上代码时,客户端可以通过浏览器或CURL命令返回对应的结果。这里以CURL命令执行。其返回结果如下:
1$ curl -i http://localhost:8080/?foo=bar
2HTTP/1.0 200 OK
3Server: BaseHTTP/0.3 Python/2.7.15
4Date: Thu, 30 Nov 2017 15:21:05 GMT
5CLIENT VALUES:
6client_address=('127.0.0.1', 54886) (localhost.localdomain)
7command=GET
8path=/?foo=bar
9real path=/
10query=foo=bar
11request_version=HTTP/1.1
12SERVER VALUES:
13server_version=BaseHTTP/0.3
14sys_version=Python/2.7.15
15protocol_version=HTTP/1.0
16HEADERS RECEIVED:
17accept=*/*
18host=localhost:8080
19user-agent=curl/7.59.0
二、HTTP POST请求
BaseHTTPServer模块有提供rfile方法读取POST数据,但功能较弱,对于文件上传类的操作,需要借助CGI模块处理。先看下rfile方法,读取POST数据的操作如下:
1datas = self.rfile.read(int(self.headers['content-length']))
2datas = urllib.unquote(datas).decode("utf-8", 'ignore')
再看个复杂的,基于cgi模块的:
1from BaseHTTPServer import BaseHTTPRequestHandler
2import cgi
3class PostHandler(BaseHTTPRequestHandler):
4 def do_POST(self):
5 # Parse the form data posted
6 form = cgi.FieldStorage(
7 fp=self.rfile,
8 headers=self.headers,
9 environ={'REQUEST_METHOD':'POST',
10 'CONTENT_TYPE':self.headers['Content-Type'],
11 })
12 # Begin the response
13 self.send_response(200)
14 self.end_headers()
15 self.wfile.write('Client: %s\n' % str(self.client_address))
16 self.wfile.write('User-agent: %s\n' % str(self.headers['user-agent']))
17 self.wfile.write('Path: %s\n' % self.path)
18 self.wfile.write('Form data:\n')
19 # Echo back information about what was posted in the form
20 for field in form.keys():
21 field_item = form[field]
22 if field_item.filename:
23 # The field contains an uploaded file
24 file_data = field_item.file.read()
25 file_len = len(file_data)
26 del file_data
27 self.wfile.write('\tUploaded %s as "%s" (%d bytes)\n' % \
28 (field, field_item.filename, file_len))
29 else:
30 # Regular form value
31 self.wfile.write('\t%s=%s\n' % (field, form[field].value))
32 return
33if __name__ == '__main__':
34 from BaseHTTPServer import HTTPServer
35 server = HTTPServer(('localhost', 8080), PostHandler)
36 print 'Starting server, use <ctrl-c> to stop'
37 server.serve_forever()</ctrl-c>
按如下命令请求后返回的结果如下:
1# curl http://localhost:8080/ -F name=www.361way.com -F foo=bar -F [email protected]
2Client: ('127.0.0.1', 55418)
3User-agent: curl/7.59.0
4Path: /
5Form data:
6 Uploaded datafile as "test.py" (1442 bytes)
7 foo=bar
8 name=www.361way.com
不过这个示例也是非常简单的只是读取了上传文件的大小,直接就进行了数据的del,并未将上传的文件进行保存。
三、多线程的使用
这里使用了SocketServer里的ThreadingMixIn方法和threading模块进行的实现。具体代码如下:
1from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
2from SocketServer import ThreadingMixIn
3import threading
4class Handler(BaseHTTPRequestHandler):
5 def do_GET(self):
6 self.send_response(200)
7 self.end_headers()
8 message = threading.currentThread().getName()
9 self.wfile.write(message)
10 self.wfile.write('\n')
11 return
12class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
13 """Handle requests in a separate thread."""
14if __name__ == '__main__':
15 server = ThreadedHTTPServer(('localhost', 8080), Handler)
16 print 'Starting server, use <ctrl-c> to stop'
17 server.serve_forever()</ctrl-c>
如下每执行一次会打印一次线程信息:
1$ curl http://localhost:8080/
2Thread-1
3$ curl http://localhost:8080/
4Thread-2
5$ curl http://localhost:8080/
6Thread-3
四、错误响应
错误响应使用的send_error方法,具体示例如下:
1from BaseHTTPServer import BaseHTTPRequestHandler
2class ErrorHandler(BaseHTTPRequestHandler):
3 def do_GET(self):
4 self.send_error(404)
5 return
6if __name__ == '__main__':
7 from BaseHTTPServer import HTTPServer
8 server = HTTPServer(('localhost', 8080), ErrorHandler)
9 print 'Starting server, use <ctrl-c> to stop'
10 server.serve_forever()</ctrl-c>
这里不再写输出结果,因为直接返回的404。
五、设置响应头
通过send_header方法,可以增加响应头内容。这里假设要发送一个Last-Modified的响应头,其内容是当前的时间戳,操作方法如下:
1from BaseHTTPServer import BaseHTTPRequestHandler
2import urlparse
3import time
4class GetHandler(BaseHTTPRequestHandler):
5 def do_GET(self):
6 self.send_response(200)
7 self.send_header('Last-Modified', self.date_time_string(time.time()))
8 self.end_headers()
9 self.wfile.write('Response body\n')
10 return
11if __name__ == '__main__':
12 from BaseHTTPServer import HTTPServer
13 server = HTTPServer(('localhost', 8080), GetHandler)
14 print 'Starting server, use <ctrl-c> to stop'
15 server.serve_forever()</ctrl-c>
本篇内容和代码主要基于pymotw翻译学习总结而来。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/basehttpserver/5790.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.