代码之家  ›  专栏  ›  技术社区  ›  MarkMark

python的simplehttpserver的get和post函数是如何工作的?

  •  1
  • MarkMark  · 技术社区  · 7 年前

    为了学习,我创建了以下小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.simplehttpprequesthandler类扩展了两个函数,即go-get和do-post
    • 函数的作用是:创建一个绑定到I.P.地址和端口的服务器处理程序对象和服务器套接字,并调用一个函数来无限期地服务/监听。

    旁白 :我通过查看python文档知道 https://docs.python.org/2/library/simplehttpserver.html 那个simplehttpserver.simplehttpprequesthandler有一个名为do-get的方法,我假设它被我的serverhandler类中的do-get重写了?

    问题 : 在幕后发生了什么事?一旦我们让这个服务器监听指向特定ip:port的http“activity”,它就会自动知道传入的信号是get还是post,一旦遇到,服务器就会调用我的do-get或do-post函数吗?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Joe Iddon    7 年前

    当你打电话 SocketServer.TCPServer ,您将 Handler 类作为接收传入请求的类。

    所有这些 SimpleHTTPServer 模块帮助你提供基本的HTTP功能,但是你可以自己编写所有的HTTP功能。

    所以,正如你所说,当你定义 处理程序 ,您将继承 SimpleHTTPRequestHandler 类,但随后重写两个预定义方法: do_GET do_POST . 也可以重写类中的任何其他方法。

    然而,这些 do_* 方法会 从未 如果不是因为 handle 方法中定义的 SimpleHttPrequestHandler 因为这个函数 socketserver 模块。

    所以如果你要继承 socketserver.BaseRequestHandler ,您将失去所有功能,因为这个类' handle() 方法不起作用:

    class socketserver.BaseRequestHandler

    手()

    此功能必须完成服务 请求。默认实现什么也不做。几个例子 属性对它可用;请求可用为 self.request;客户地址为self.client_address;和 服务器实例作为self.server,以防需要访问每台服务器 信息。

    所以,通过导入 SimpleHttPrequestHandler SimpleHttpServer服务器 模块,您将立即获得http服务器的基本功能。

    所有这些功能都记录在案 here 有一个重要的位 手柄 方法:

    class http.server.BaseHTTPRequestHandler(request, client_address, server)

    手()

    调用handle_one_request()一次(或者,如果是持久的 多次启用连接,以处理传入的HTTP 请求。您不应该重写它;相反,应该实现 适当的方法。

    handle_one_request()

    此方法将解析并分派请求 以适当的方式。 你永远不应该超越 它。

    最后,在分解了 socketserver.TCPServer 将调用 手() 方法 无论什么 你通过了,我们就知道 SimpleHttPrequestHandler 在将请求传递到适当的 多吉特 , 多斯波斯特 或任何依赖于请求头的方法。


    如果您想了解如何自己实现这一点,请查看源代码,或者 /usr/lib/pythonX.Y/http/server.py 或在 GitHub .

    我们可以看到他们的 SimpleHttpServer服务器 继承 BaseHTTPServer 在那里 手() 处理一个请求() 方法定义如下:

    所以,正如医生所描述的, 手柄 只是把请求传递给 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()
    

    以及 处理一个请求 是哪里 多伊* 方法被调用:

    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
    

    (注意,我是双重散列的( ## “我的意见是把它们与原作者分开。”