python BaseHTTPServer模块

BaseHTTPServer类是在SocketServer的基础上创建出的一个简单的HTTP servers应用类,而通过BaseHTTPRequestHandler方法我们可以直接实现GET、POST等请求。由于其只是一个简单的SocketServer.TCPServer子类,它本身并不支持多线程或多进程,如果想使用多线程或多进程,需要结合threading模块去fork,这在后面也会提到。

一、HTTP GET请求

代码如下:
from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
class GetHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        parsed_path = urlparse.urlparse(self.path)
        message_parts = [
                'CLIENT VALUES:',
                'client_address=%s (%s)' % (self.client_address,
                                            self.address_string()),
                'command=%s' % self.command,
                'path=%s' % self.path,
                'real path=%s' % parsed_path.path,
                'query=%s' % parsed_path.query,
                'request_version=%s' % self.request_version,
                '',
                'SERVER VALUES:',
                'server_version=%s' % self.server_version,
                'sys_version=%s' % self.sys_version,
                'protocol_version=%s' % self.protocol_version,
                '',
                'HEADERS RECEIVED:',
                ]
        for name, value in sorted(self.headers.items()):
            message_parts.append('%s=%s' % (name, value.rstrip()))
        message_parts.append('')
        message = '\r\n'.join(message_parts)
        self.send_response(200)
        self.end_headers()
        self.wfile.write(message)
        return
if __name__ == '__main__':
    from BaseHTTPServer import HTTPServer
    server = HTTPServer(('localhost', 8080), GetHandler)
    print 'Starting server, use  to stop'
    server.serve_forever()
其中wfile方法用于向客户端返回信息,send_response返回对应的http代码。上面的监听地址可以跟据自已的需求进行修改。当我们运行以上代码时,客户端可以通过浏览器或CURL命令返回对应的结果。这里以CURL命令执行。其返回结果如下:



<br />
$ curl -i http://localhost:8080/?foo=bar
HTTP/1.0 200 OK
Server: BaseHTTP/0.3 Python/2.7.15
Date: Thu, 30 Nov 2017 15:21:05 GMT
CLIENT VALUES:
client_address=('127.0.0.1', 54886) (localhost.localdomain)
command=GET
path=/?foo=bar
real path=/
query=foo=bar
request_version=HTTP/1.1
SERVER VALUES:
server_version=BaseHTTP/0.3
sys_version=Python/2.7.15
protocol_version=HTTP/1.0
HEADERS RECEIVED:
accept=*/*
host=localhost:8080
user-agent=curl/7.59.0

二、HTTP POST请求

BaseHTTPServer模块有提供<a href="https://docs.python.org/2/library/basehttpserver.html" target="_blank" rel="noopener">rfile方法</a>读取POST数据,但功能较弱,对于文件上传类的操作,需要借助CGI模块处理。先看下rfile方法,读取POST数据的操作如下:



<br />
datas = self.rfile.read(int(self.headers['content-length']))
datas = urllib.unquote(datas).decode("utf-8", 'ignore')
再看个复杂的,基于cgi模块的:



<br />
from BaseHTTPServer import BaseHTTPRequestHandler
import cgi
class PostHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        # Parse the form data posted
        form = cgi.FieldStorage(
            fp=self.rfile,
            headers=self.headers,
            environ={'REQUEST_METHOD':'POST',
                     'CONTENT_TYPE':self.headers['Content-Type'],
                     })
        # Begin the response
        self.send_response(200)
        self.end_headers()
        self.wfile.write('Client: %s\n' % str(self.client_address))
        self.wfile.write('User-agent: %s\n' % str(self.headers['user-agent']))
        self.wfile.write('Path: %s\n' % self.path)
        self.wfile.write('Form data:\n')
        # Echo back information about what was posted in the form
        for field in form.keys():
            field_item = form[field]
            if field_item.filename:
                # The field contains an uploaded file
                file_data = field_item.file.read()
                file_len = len(file_data)
                del file_data
                self.wfile.write('\tUploaded %s as "%s" (%d bytes)\n' % \
                        (field, field_item.filename, file_len))
            else:
                # Regular form value
                self.wfile.write('\t%s=%s\n' % (field, form[field].value))
        return
if __name__ == '__main__':
    from BaseHTTPServer import HTTPServer
    server = HTTPServer(('localhost', 8080), PostHandler)
    print 'Starting server, use  to stop'
    server.serve_forever()
按如下命令请求后返回的结果如下:



<br />
# curl http://localhost:8080/ -F name=www.361way.com -F foo=bar -F  datafile=@test.py
Client: ('127.0.0.1', 55418)
User-agent: curl/7.59.0
Path: /
Form data:
    Uploaded datafile as "test.py" (1442 bytes)
    foo=bar
    name=www.361way.com

不过这个示例也是非常简单的只是读取了上传文件的大小,直接就进行了数据的del,并未将上传的文件进行保存。

<br />

三、多线程的使用

这里使用了SocketServer里的ThreadingMixIn方法和threading模块进行的实现。具体代码如下:



<br />
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import threading
class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        message =  threading.currentThread().getName()
        self.wfile.write(message)
        self.wfile.write('\n')
        return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""
if __name__ == '__main__':
    server = ThreadedHTTPServer(('localhost', 8080), Handler)
    print 'Starting server, use  to stop'
    server.serve_forever()
如下每执行一次会打印一次线程信息:



<br />
$ curl http://localhost:8080/
Thread-1
$ curl http://localhost:8080/
Thread-2
$ curl http://localhost:8080/
Thread-3

四、错误响应

错误响应使用的send_error方法,具体示例如下:



<br />
from BaseHTTPServer import BaseHTTPRequestHandler
class ErrorHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_error(404)
        return
if __name__ == '__main__':
    from BaseHTTPServer import HTTPServer
    server = HTTPServer(('localhost', 8080), ErrorHandler)
    print 'Starting server, use  to stop'
    server.serve_forever()
这里不再写输出结果,因为直接返回的404。

五、设置响应头

通过send_header方法,可以增加响应头内容。这里假设要发送一个Last-Modified的响应头,其内容是当前的时间戳,操作方法如下:



<br />
from BaseHTTPServer import BaseHTTPRequestHandler
import urlparse
import time
class GetHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Last-Modified', self.date_time_string(time.time()))
        self.end_headers()
        self.wfile.write('Response body\n')
        return
if __name__ == '__main__':
    from BaseHTTPServer import HTTPServer
    server = HTTPServer(('localhost', 8080), GetHandler)
    print 'Starting server, use  to stop'
    server.serve_forever()

本篇内容和代码主要基于pymotw翻译学习总结而来。

<br />

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注