python - python 的 SimpleHTTPServer do_GET 和 do_POST 函数是如何工作的?
问题描述
出于学习目的,我创建了以下小型 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”类通过 go_GET 和 do_POST 这两个函数扩展了 SimpleHTTPServer.SimpleHTTPRequestHandler 类
- main() 函数创建一个绑定到我选择的 IP 地址和端口的服务器处理程序对象和服务器套接字,并调用一个函数来无限期地服务/侦听。
旁白:我通过查看 Python 文档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
. 您还可以覆盖类中的任何其他方法。
但是,如果不是在中定义的方法,这些do_*
方法将永远不会被调用,因为它是由模块调用的这个函数。handle
SimpleHTTPRequestHandler
socketserver
所以如果你只是继承socketserver.BaseRequestHandler
,你会失去所有的功能,因为这个类的handle()
方法什么都不做:
class socketserver.BaseRequestHandler
...
handle()
此功能必须完成为请求提供服务所需的所有工作。默认实现什么也不做。它有几个实例属性可用;该请求可作为 self.request 获得;客户端地址为 self.client_address;服务器实例为 self.server,以防它需要访问每个服务器的信息。
...
SimpleHTTPRequestHandler
因此,通过从模块导入SimpleHTTPServer
,您可以立即获得 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
如果您想了解如何自己实现此功能,请查看GitHub/usr/lib/pythonX.Y/http/server.py
中或上的源代码。
我们可以在那里看到它们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
(注意,我对我的评论进行了双重哈希(##
)以将它们与原作者的评论区分开来)
推荐阅读
- c++ - 当需要指向函数的指针时如何将指针传递给函数成员
- ios - 我可以让我的 iOS 应用程序仅在 iPhone 6 和更新机型上可用吗?
- django - 从另一个应用程序 Django 导入模型
- reactjs - 如何在 React 中从闭包中访问状态
- node.js - Webpack 生产构建失败:“无法解析 'aws-sdk'”
- php - Laravel 验证扩展正则表达式
- spring-mvc - 如何使用 OAuth“授权”方法获取谁正在尝试登录?
- cmake - 如何将外部 CMake 项目安装到 CMAKE_CURRENT_BINARY_DIR
- python - 根据特定列对熊猫数据框进行排名和排序
- unity3d - Unity 2018.1:按钮在所有画布中都没有响应,但第一个