SimpleHTTPRequestHandler在do_POST方法返回前关闭连接

9 投票
2 回答
12680 浏览
提问于 2025-04-16 20:56

我正在用Python写一个简单的网页服务器。下面是我代码的简化版本:

class StreamerHandler(SimpleHTTPRequestHandler):
    def do_POST(self):
        try:
            length = int(self.headers.getheader('content-length'))
            data = self.rfile.read(length)
            self.send_response(200, "OK")
            #process_data(data, self.client_address)
        except Exception as inst:
            logging.error(type(self).__name__ + "/"  + type(inst).__name__ + " (" + inst.__str__() + ")")

class Streamer(TCPServer):
    def __init__(self, overlay):
        self.allow_reuse_address = True
        TCPServer.__init__(self, ("", port), StreamerHandler)

我想做的是先发送响应,然后关闭TCP连接,接着再运行一个叫process_data的方法,这个方法可能需要很长时间才能完成。

有没有办法做到这一点?我能想到的唯一解决方案就是用一个专门的线程来处理这个过程。

2 个回答

3

首先,SimpleHTTPRequestHandler 是从 BaseHTTPServer.BaseHTTPRequestHandler 这个类继承而来的,而 BaseHTTPRequestHandler 又是从 SocketServer.StreamRequestHandler 这个类继承的。

SocketServer.StreamRequestHandler 里,rfilewfile 这两个伪文件是在 setup() 方法中通过一个叫 self.connection 的套接字对象创建的:

def setup(self):
    self.connection = self.request
    if self.timeout is not None:
        self.connection.settimeout(self.timeout)
    if self.disable_nagle_algorithm:
        self.connection.setsockopt(socket.IPPROTO_TCP,
                                   socket.TCP_NODELAY, True)
    self.rfile = self.connection.makefile('rb', self.rbufsize)
    self.wfile = self.connection.makefile('wb', self.wbufsize)

这个套接字 self.connection 仍然可以使用,所以你可以调用 self.connection.close() 来关闭它。不过,wfile 这个伪文件里面可能有一些缓存的数据,如果直接关闭可能会丢失这些数据。因此,你应该调用 self.finish(),这个方法也是在 SocketServer.StreamRequestHandler 中定义的:

def finish(self):
    if not self.wfile.closed:
        self.wfile.flush()
    self.wfile.close()
    self.rfile.close()

所以,我觉得下面的代码应该可以工作(虽然还没测试过):

class StreamerHandler(SimpleHTTPRequestHandler):
    def do_POST(self):
        try:
            length = int(self.headers.getheader('content-length'))
            data = self.rfile.read(length)
            self.send_response(200, "OK")
            self.finish()
            process_data(data, self.client_address)
        except Exception as exc:
            logging.error(
                "{0}/{1}({2})".format(
                    type(self).__name__, type(exc).__name__, str(exc)))
7

我试了一下,实际上你需要按顺序执行这两个命令才能关闭它:

self.finish() self.connection.close()

撰写回答