python 的 SimpleHTTPServer do_GET 和 do_POST 函数如何工作?
How does python's SimpleHTTPServer do_GET and do_POST functions work?
出于学习目的,我创建了以下小型 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()
我的假设如下:
- 我的 class 'ServerHandler' 通过两个函数扩展了 SimpleHTTPServer.SimpleHTTPRequestHandler class,即 go_GET 和 do_POST
- main() 函数创建一个服务器处理程序对象和绑定到我的 I.P 的服务器套接字。地址和选择的端口,并无限期地调用函数 serve/listen。
旁白:我通过查看 Python 文档 https://docs.python.org/2/library/simplehttpserver.html 知道 SimpleHTTPServer.SimpleHTTPRequestHandler 有一个名为 do_GET 的方法,我假设它被我的 ServerHandler class?
中的 do_GET 覆盖了
问题:
do_GET 和 do_POST 背后发生了什么?是不是一旦我们让这个服务器侦听指向特定 IP:PORT 的 HTTP "activity" ,它就会自动知道传入信号是 GET 还是 POST 并且一旦是遇到服务器调用我的 do_GET 或 do_POST 函数?
当您调用 SocketServer.TCPServer
时,您将 Handler
class 指定为 class 以接收传入请求。
SimpleHTTPServer
模块为您提供的全部帮助是提供基本的 HTTP 功能,但您可以自己编写所有这些功能。
所以,正如您所说,当您定义 Handler
时,您继承了 SimpleHTTPRequestHandler
class 的所有方法,但随后覆盖了 pre-defined 中的两个方法方法:do_GET
和 do_POST
。您还可以覆盖 class.
中的任何其他方法
但是,如果 SimpleHTTPRequestHandler
中定义的 handle
方法不是这样,这些 do_*
方法将 永远不会被调用 socketserver
模块 就是 调用的这个函数。
因此,如果您只是继承 socketserver.BaseRequestHandler
,您将失去所有功能,因为此 class' handle()
方法什么都不做:
class socketserver.BaseRequestHandler
...
handle()
This function must do all the work required to service a
request. The default implementation does nothing. Several instance
attributes are available to it; the request is available as
self.request; the client address as self.client_address; and the
server instance as self.server, in case it needs access to per-server
information.
...
因此,通过从 SimpleHTTPServer
模块导入 SimpleHTTPRequestHandler
,您可以立即获得 HTTP 服务器的基本功能。
所有这些功能都记录在案 here,其 handle
方法中有重要一点:
class http.server.BaseHTTPRequestHandler(request, client_address, server)
...
handle()
Calls handle_one_request() once (or, if persistent
connections are enabled, multiple times) to handle incoming HTTP
requests. You should never need to override it; instead, implement
appropriate do_*() methods.
handle_one_request()
This method will parse and dispatch the request
to the appropriate do_*() method. You should never need to override
it.
...
所以最后,在分解 socketserver.TCPServer
将如何为 调用 handle()
方法之后 无论什么 class 你传递它,我们看到SimpleHTTPRequestHandler
如何将请求传递到适当的 do_GET
、do_POST
或任何方法,具体取决于请求的 headers。
如果您想了解如何自己实现,请查看 /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
(注意,我double-hashed(##
)我的评论将它们与原作者的分开)
出于学习目的,我创建了以下小型 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()
我的假设如下:
- 我的 class 'ServerHandler' 通过两个函数扩展了 SimpleHTTPServer.SimpleHTTPRequestHandler class,即 go_GET 和 do_POST
- main() 函数创建一个服务器处理程序对象和绑定到我的 I.P 的服务器套接字。地址和选择的端口,并无限期地调用函数 serve/listen。
旁白:我通过查看 Python 文档 https://docs.python.org/2/library/simplehttpserver.html 知道 SimpleHTTPServer.SimpleHTTPRequestHandler 有一个名为 do_GET 的方法,我假设它被我的 ServerHandler class?
中的 do_GET 覆盖了问题: do_GET 和 do_POST 背后发生了什么?是不是一旦我们让这个服务器侦听指向特定 IP:PORT 的 HTTP "activity" ,它就会自动知道传入信号是 GET 还是 POST 并且一旦是遇到服务器调用我的 do_GET 或 do_POST 函数?
当您调用 SocketServer.TCPServer
时,您将 Handler
class 指定为 class 以接收传入请求。
SimpleHTTPServer
模块为您提供的全部帮助是提供基本的 HTTP 功能,但您可以自己编写所有这些功能。
所以,正如您所说,当您定义 Handler
时,您继承了 SimpleHTTPRequestHandler
class 的所有方法,但随后覆盖了 pre-defined 中的两个方法方法:do_GET
和 do_POST
。您还可以覆盖 class.
但是,如果 SimpleHTTPRequestHandler
中定义的 handle
方法不是这样,这些 do_*
方法将 永远不会被调用 socketserver
模块 就是 调用的这个函数。
因此,如果您只是继承 socketserver.BaseRequestHandler
,您将失去所有功能,因为此 class' handle()
方法什么都不做:
class socketserver.BaseRequestHandler
...
handle()
This function must do all the work required to service a request. The default implementation does nothing. Several instance attributes are available to it; the request is available as self.request; the client address as self.client_address; and the server instance as self.server, in case it needs access to per-server information.
...
因此,通过从 SimpleHTTPServer
模块导入 SimpleHTTPRequestHandler
,您可以立即获得 HTTP 服务器的基本功能。
所有这些功能都记录在案 here,其 handle
方法中有重要一点:
class http.server.BaseHTTPRequestHandler(request, client_address, server)
...
handle()
Calls handle_one_request() once (or, if persistent connections are enabled, multiple times) to handle incoming HTTP requests. You should never need to override it; instead, implement appropriate do_*() methods.
handle_one_request()
This method will parse and dispatch the request to the appropriate do_*() method. You should never need to override it.
...
所以最后,在分解 socketserver.TCPServer
将如何为 调用 handle()
方法之后 无论什么 class 你传递它,我们看到SimpleHTTPRequestHandler
如何将请求传递到适当的 do_GET
、do_POST
或任何方法,具体取决于请求的 headers。
如果您想了解如何自己实现,请查看 /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
(注意,我double-hashed(##
)我的评论将它们与原作者的分开)