【问题标题】:Python BaseHTTPServer.HTTPServer - callback for start and stop eventPython BaseHTTPServer.HTTPServer - 开始和停止事件的回调
【发布时间】:2013-05-24 08:35:50
【问题描述】:

参考:http://docs.python.org/2/library/basehttpserver.html

我有以下代码 sn-p,它使用Python BaseHTTPServer 运行基本的 HTTP 服务器。

from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler

# http request handler
class HttpHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        print "I have just received a HTTP request through POST"

try:
    server = HTTPServer((<ip>, <port>), HttpHandler)

    # wait forever for incoming http requests!
    server.serve_forever()

except KeyboardInterrupt:
    server.socket.close()

我正在寻找的是一种在使用 server.serve_forever()/server.socket.close() 方法启动/停止 http 服务器时获取回调的方法。

假设我们有以下函数:

def http_server_start_callback():
    print "http server has just been started" 

def http_server_stop_callback():
    print "http server has just been stopped" 

我希望http_server_start_callback 函数在我启动服务器后立即调用,即server.serve_forever(),我希望http_server_stop_callback 函数在我停止服务器后立即调用,即server.socket.close()

最好使用以下回调配置 http 服务器:

  • 在启动服务器之前
  • 启动服务器后
  • 停止服务器之前
  • 停止服务器后

有没有办法在Python BaseHTTPServer.HTTPServer 中设置这些回调?!

【问题讨论】:

    标签: python http callback basehttpserver


    【解决方案1】:

    最好使用以下配置http服务器 回调:

    • 在启动服务器之前
    • 启动服务器后
    • 停止服务器之前
    • 停止服务器后

    请记住,操作系统将在套接字开始侦听的那一刻开始接受和排队 TCP 连接,这是在 BaseHTTPServer 的构造函数中完成的,所以如果你想在启动服务器之前执行冗长的任务,它可能会更好在操作系统开始接受连接之前执行它们。

    有一个server_activate() 方法可以调用socket.listen(),所以最好覆盖它。

    同样,操作系统将继续接受连接,直到调用 socket.close(),所以如果您希望能够定义一个能够防止自身被关闭的“预停止”处理程序,它可能会更好使用server_close()方法,而不是直接调用socket.close()

    我整理了一个简单的示例,使用请求处理程序上的类方法来处理四个新事件,尽管您可以将它们移动到其他地方...

    from BaseHTTPServer import HTTPServer
    from BaseHTTPServer import BaseHTTPRequestHandler
    
    # Subclass HTTPServer with some additional callbacks
    class CallbackHTTPServer(HTTPServer):
    
        def server_activate(self):
            self.RequestHandlerClass.pre_start()
            HTTPServer.server_activate(self)
            self.RequestHandlerClass.post_start()
    
        def server_close(self):
            self.RequestHandlerClass.pre_stop()
            HTTPServer.server_close(self)
            self.RequestHandlerClass.post_stop()
    
    
    # HTTP request handler
    class HttpHandler(BaseHTTPRequestHandler):
    
        @classmethod
        def pre_start(cls):
            print 'Before calling socket.listen()'
    
        @classmethod
        def post_start(cls):
            print 'After calling socket.listen()'
    
        @classmethod
        def pre_stop(cls):
            print 'Before calling socket.close()'
    
        @classmethod
        def post_stop(cls):
            print 'After calling socket.close()'
    
        def do_POST(self):
            print "I have just received an HTTP POST request"
    
    
    def main():
    
        # Create server
        try:
            print "Creating server"
            server = CallbackHTTPServer(('', 8000), HttpHandler)
        except KeyboardInterrupt:
            print "Server creation aborted"
            return
    
        # Start serving
        try:
            print "Calling serve_forever()"
            server.serve_forever()
        except KeyboardInterrupt:
            print "Calling server.server_close()"
            server.server_close()
    
    
    if __name__ == '__main__':
        main()
    

    请注意,我还将对构造函数的调用移至其自己的 try...except 块中,因为如果在构造过程中按 CTRL-C,server 变量将不存在。

    【讨论】:

    • 感谢您的解决方案。假设我运行这个脚本。那么服务器文件夹在哪里呢?我的意思是,我有一个文件(比如“numbers.txt”)。我将把它添加到服务器文件夹并调用它(比如“localhost/numbers.txt”)。
    【解决方案2】:

    你必须继承 HTTPServer 并使用你的类而不是 HTTPServer

    from __future__ import print_function
    from BaseHTTPServer import HTTPServer
    from BaseHTTPServer import BaseHTTPRequestHandler
    
    
    class MyHTTPServer(HTTPServer):
    
    
        def __init__(self, *args, **kwargs):
    
            self.on_before_serve = kwargs.pop('on_before_serve', None)
            HTTPServer.__init__(self, *args, **kwargs)
    
        def serve_forever(self, poll_interval=0.5):
    
            if self.on_before_serve:
                self.on_before_serve(self)
            HTTPServer.serve_forever(self, poll_interval)
    
    
    # http request handler
    class HttpHandler(BaseHTTPRequestHandler):
        def do_POST(self):
            print("I have just received a HTTP request through POST")
    
    try:
        server = MyHTTPServer(('0.0.0.0', 8080), HttpHandler,
                              on_before_serve = lambda server: print('Server will start to serve in the moment...'))
    
        # wait forever for incoming http requests!
        server.serve_forever()
    
    except KeyboardInterrupt:
        server.socket.close()
    

    【讨论】:

    • 如果回调工具不能作为HTTPServer 的一部分使用,那么可以通过在使用@987654325 启动服务器之前调用回调函数来轻松伪造启动前和停止后回调@ 并在使用 socket.close() 停止服务器后立即。但棘手的是启动后和停止前的回调。因为serve_forever() 是一个阻塞函数调用,之后的任何代码都无法访问。那么有什么方法可以覆盖启动后(和停止前)回调?
    • 启动后和停止前回调有什么用例?
    • @PiotrDobrogost 在我的情况下,我想在日志中写入服务器已成功启动。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 2019-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多