出于学习目的,我创建了以下小型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()
我的假设如下:
放在一边:通过查看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功能?
答案 0 :(得分:1)
呼叫SocketServer.TCPServer
时,您将Handler
类分配为接收传入请求的类。
SimpleHTTPServer
模块为您提供的所有帮助都提供了基本的HTTP功能,但是您可以自己编写所有这些功能。
因此,正如您所说,在定义Handler
时,您将从SimpleHTTPRequestHandler
类继承所有方法,但随后覆盖了两个预定义方法:do_GET
和do_POST
。您还可以覆盖该类中的其他任何方法。
但是,如果不是do_*
中定义的handle
方法的话,这些SimpleHTTPRequestHandler
方法就永远不会被调用,因为正是这个函数由socketserver
模块调用 。
因此,如果您仅继承socketserver.BaseRequestHandler
,则将失去所有功能,因为此类的handle()
方法不会执行任何操作:
class socketserver.BaseRequestHandler
...
handle()
此功能必须完成维修保养所需的所有工作。 请求。默认实现不执行任何操作。几个实例 属性可用;该请求可作为 自我要求客户地址为self.client_address;和 服务器实例作为self.server,以防需要访问每个服务器 信息。
...
因此,通过从SimpleHTTPRequestHandler
模块导入SimpleHTTPServer
,您将立即获得HTTP服务器的基本功能。
所有这些功能都已记录在here中,并且在其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
(请注意,我将自己的评论加了双阴影线(##
,以将其与原始作者的评论区分开来)