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

httpserver.run需要basehttpRequestHandler类,而不是对象

  •  2
  • tangoal  · 技术社区  · 6 年前

    我有一个从baseHttpRequestHandler派生的类,它实现了我的特定get方法。这很管用:

    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class MyHTTPRequestHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            """ my implementation of the GET method """
    
    myServer = HTTPServer(("127.0.0.1", 8099), MyHTTPRequestHandler)
    myServer.handle_request()
    

    但是为什么我要通过我的班 MyHTTPRequestHandler HTTPServer ?我知道这是 documentation :

    类http.server.basehttpRequestHandler(请求、客户端地址、服务器)

    此类用于处理到达服务器的HTTP请求。它本身不能响应任何实际的HTTP请求;它 必须子类化才能处理每个请求方法(例如get或post)。 BaseHttpRequestHandler提供了许多类和实例 子类使用的变量和方法。

    处理程序将解析请求和头,然后调用特定于请求类型的方法。方法名是构造的 来自请求。例如,对于请求方法spam, 将不带参数调用do-spam()方法。所有相关的 信息存储在处理程序的实例变量中。子类 不需要重写或扩展 初始化 ()方法。

    但是 我想传递一个实例化的对象 而是我的子类。我不明白为什么这个设计是那样的,对我来说它看起来像设计失败。具有多形态的面向对象编程的目的是我可以通过子类来实现具有相同接口的特定行为,因此在我看来这是不必要的限制。

    这就是我想要的:

    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class MyHTTPRequestHandler(BaseHTTPRequestHandler):
        def __init__(self, myAdditionalArg):
            self.myArg = myAdditionalArg
    
        def do_GET(self):
            """ my implementation of the GET method """
            self.wfile(bytes(self.myArg, "utf-8"))
            # ...
    
    myReqHandler = MyHTTPRequestHandler("mySpecificString")
    myServer = HTTPServer(("127.0.0.1", 8099), myReqHandler)
    myServer.handle_request()
    

    但如果我这样做,显然我收到了预期的错误消息:

    类型错误:“MyHttpRequestHandler”对象不可调用

    如何解决这个问题,以便我仍然可以使用打印特定字符串? 我需要这个还有第二个原因:我想要那个 myhttpRequestHandler 还提供有关客户端的详细信息,该客户端使用get方法从服务器检索数据(我希望检索客户端浏览器的HTTP头)。

    我只有一个客户机,它向服务器启动一个请求。如果一个解决方案能在更一般的环境下工作,我会很高兴,但我不会 我现在的项目需要它。

    有人知道怎么做吗?

    2 回复  |  直到 6 年前
        1
  •  1
  •   e.s.    6 年前

    服务器需要根据需要创建请求处理程序来处理所有传入的请求。只有一个请求处理程序是不好的设计。如果您传入了一个实例,那么服务器一次只能处理一个请求,如果有任何副作用,就会非常糟糕。任何类型的状态更改都超出了请求处理程序应该做的工作范围。

    BaseHTTPRequestHandler 具有处理消息日志记录的方法和属性 self.headers 包含所有标题信息。它默认将消息记录到 sys.stderr ,所以你可以 $ python -m my_server.py 2> log_file.txt 以捕获日志消息。或者,您可以用自己的处理程序写入文件。

    class MyHTTPRequestHandler(BaseHTTPRequestHandler):
        log_file = os.path.join(os.path.abspath(''), 'log_file.txt')  # saves in directory where server is
        myArg = 'some fancy thing'                    
    
        def do_GET(self):
            # do things
            self.wfile.write(bytes(self.myArg,'utf-8'))
            # do more
            msg_format = 'start header:\n%s\nend header\n'
            self.log_message(msg_format, self.headers)
    
        def log_message(self, format_str, *args):  # This is basically a copy of original method, just changing the destination
            with open(self.log_file, 'a') as logger:
                logger.write("%s - - [%s] %s\n" %
                            self.log_date_time_string(),
                            format%args))
    
    handler = MyHTTPRequestHandler
    myServer = HTTPServer(("127.0.0.1", 8099), handler)  
    
        2
  •  0
  •   tangoal    6 年前

    可以得出一个特定的 HTTPServer 类( MyHttpServer ,具有以下属性:

    • myArg :由HTTP打印的特定“消息文本” 请求处理程序
    • headers :存储由 HTTP请求处理程序

    服务器类必须与 MyHTTPRequestHandler . 此外,只有在以下条件下,实施才能正常工作:

    • 只有一个HTTP请求处理程序同时从服务器请求响应(否则属性保留的数据会损坏)
    • myhttpRequestHandler 仅用于 myhttpserver(myhttpserver) 反之亦然(否则可能发生异常或数据损坏等未知副作用)

    这就是为什么两个类必须以这样的方式打包和装运在一起:

    from http.server import BaseHTTPRequestHandler, HTTPServer
    
    class MyHTTPRequestHandler(BaseHTTPRequestHandler):
        def do_GET(self):
            self.wfile.write(bytes(self.server.myArg, 'utf-8'))
            #...
            self.server.headers = self.headers
    
    class MyHttpServer(HTTPServer):
        def __init__(self, server_address, myArg, handler_class=MyHttpRequestHandler):
            super().__init__(server_address, handler_class)
            self.myArg = myArg
            self.headers = dict()
    

    这些类的用法可能如下所示,而服务器只响应客户机(即Web浏览器)的一个请求:

    def get_header():
        httpd = MyHttpServer(("127.0.0.1", 8099), "MyFancyText", MyHttpRequestHandler)
        httpd.handle_request()
        return httpd.headers