我创建了以下小HTTP服务器用于学习目的:
import SimpleHTTPServer
import SocketServer
class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
print(self.headers)
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
print(self.headers)
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
def main():
port = 50738
Handler = ServerHandler(1000)
httpd = SocketServer.TCPServer(("192.168.X.Y", port), Handler)
print "serving at port", port
httpd.serve_forever()
if __name__ == "__main__":
main()
我的假设如下:
- 我的类"ServerHandler"通过两个函数扩展了SimpleHTTPServer.SimpleHTTPRequestHandler类,即go_GET和do_POST
- main(( 函数创建一个服务器处理程序对象和服务器套接字绑定到我的 I.P. 地址和所选端口,并调用一个函数无限期地服务/侦听。
旁白:通过查看 Python DOC https://docs.python.org/2/library/simplehttpserver.html 我知道 SimpleHTTPServer.SimpleHTTPRequestHandler 有一个名为 do_GET 的方法,我认为它被我的 ServerHandler 类中的do_GET覆盖了?
问题: 与do_GET和do_POST有关的引擎盖下发生了什么?是不是这样,一旦我们让这个服务器侦听指向特定 IP:PORT 的 HTTP"活动",它就会自动知道传入信号是 GET 还是 POST,一旦遇到,服务器就会调用我的do_GET或do_POST函数?
当您调用SocketServer.TCPServer
时,您将Handler
类指定为接收传入请求的类。
SimpleHTTPServer
模块为您提供的所有帮助都是提供基本的HTTP功能,但您可以自己编写所有这些功能。
因此,正如您所说,当您定义Handler
时,您将继承SimpleHTTPRequestHandler
类中的所有方法,但随后覆盖两个预定义的方法:do_GET
和do_POST
。您还可以重写类中的任何其他方法。
但是,如果不是在SimpleHTTPRequestHandler
中定义的handle
方法,则永远不会调用这些do_*
方法,因为socketserver
模块调用的是此函数。
因此,如果您只是继承socketserver.BaseRequestHandler
,您将丢失所有功能,因为此类的handle()
方法不执行任何操作:
class socketserver.BaseRequestHandler
。
handle()
此函数必须完成为 请求。默认实现不执行任何操作。多个实例 属性可供其使用;该请求可用作 自我请求;客户端地址为self.client_address;和 服务器实例作为 self.server,以防它需要访问每个服务器 信息。
。
因此,通过从SimpleHTTPServer
模块导入SimpleHTTPRequestHandler
,您可以立即获得 HTTP 服务器的基本功能。
所有这些功能都记录在这里,其中有一个重要的关于其handle
方法:
class http.server.BaseHTTPRequestHandler(request, client_address, server)
。
handle()
调用 handle_one_request(( 一次(或者,如果持久调用( 多次启用连接以处理传入的 HTTP 请求。你永远不需要覆盖它;相反,实施 适当的 do_*(( 方法。
handle_one_request()
此方法将解析和调度请求 到适当的 do_*(( 方法。你永远不需要覆盖 它。
。
所以最后,在分解了socketserver.TCPServer
将如何为你传递它的任何类调用handle()
方法之后,我们看到SimpleHTTPRequestHandler
如何实现它,将请求传递给适当的do_GET
、do_POST
或任何方法,具体取决于请求的标头。
如果您想了解如何自己实现这一点,请查看源代码,无论是在/usr/lib/pythonX.Y/http/server.py
还是在 GitHub 上。
我们可以在那里看到他们的SimpleHTTPServer
继承了什么BaseHTTPServer
这是定义handle()
和handle_one_request()
方法的地方:
因此,正如文档所述,handle
只是将请求传递给handle_one_request
,直到连接关闭:
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = True
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
handle_one_request
是调用do_*
方法的地方:
def handle_one_request(self):
"""Handle a single HTTP request.
You normally don't need to override this method; see the class
__doc__ string for information on how to handle specific HTTP
commands such as GET and POST.
"""
try:
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
return
if not self.raw_requestline:
self.close_connection = True
return
if not self.parse_request():
# An error code has been sent, just exit
return
mname = 'do_' + self.command ## the name of the method is created
if not hasattr(self, mname): ## checking that we have that method defined
self.send_error(
HTTPStatus.NOT_IMPLEMENTED,
"Unsupported method (%r)" % self.command)
return
method = getattr(self, mname) ## getting that method
method() ## finally calling it
self.wfile.flush() #actually send the response if not already done.
except socket.timeout as e:
#a read or a write timed out. Discard this connection
self.log_error("Request timed out: %r", e)
self.close_connection = True
return
(注意,我双重散列(##
(我的评论以将它们与原作者的评论分开(