2011-05-19 88 views
12

我建立一个短网址翻译引擎在Python,和我看到的“断管”的错误一吨,而且最好使用BaseHTTPServer类时如何捕获我很好奇。这是不是整个代码,但给你的我在做什么,到目前为止的想法:Python BaseHTTPServer,我如何捕获/陷阱“破管”错误?

from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer 
    import memcache 

    class clientThread(BaseHTTPRequestHandler): 

      def do_GET(self): 
        content = None 
        http_code,response_txt,long_url = \ 
          self.ag_trans_url(self.path,content,'GET') 
        self.http_output(http_code, response_txt, long_url) 
        return 

      def http_output(self,http_code,response_txt,long_url): 
        self.send_response(http_code) 
        self.send_header('Content-type','text/plain') 
        if long_url: 
          self.send_header('Location', long_url) 
        self.end_headers() 
        if response_txt: 
          self.wfile.write(response_txt) 
        return 

     def ag_trans_url(self, orig_short_url, post_action, getpost): 
       short_url = 'http://foo.co' + orig_short_url 

       # fetch it from memcache 
       long_url = mc.get(short_url) 

       # other magic happens to look it up from db if there was nothing 
       # in memcache, etc 
       return (302, None, log_url) 

def populate_memcache() 
     # connect to db, do lots of mc.set() calls 

def main(): 
     populate_memcache() 
     try: 
       port = 8001 
       if len(sys.argv) > 1: 
         port = int(sys.argv[1]) 
       server = HTTPServer(('',port), clientThread) 
       #server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
       print '[',str(datetime.datetime.now()),'] short url processing has begun' 

       server.serve_forever() 
     except KeyboardInterrupt,SystemExit: 
       print '^C received, shutting down server' 
       server.socket.close() 

本身的伟大工程的代码,但在开始时,生产几乎立即引发错误:

Traceback (most recent call last): 
    File "/usr/lib/python2.5/SocketServer.py", line 222, in handle_request 
    self.process_request(request, client_address) 
    File "/usr/lib/python2.5/SocketServer.py", line 241, in process_request 
    self.finish_request(request, client_address) 
    File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/lib/python2.5/SocketServer.py", line 522, in __init__ 
    self.handle() 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle 
    self.handle_one_request() 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 310, in handle_one_request 
    method() 
    File "/opt/short_url_redirector/shorturl.py", line 38, in do_GET 
    self.http_output(http_code, response_txt, long_url) 
    File "/opt/short_url_redirector/shorturl.py", line 52, in http_output 
    self.send_response(http_code) 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 370, in send_response 
    self.send_header('Server', self.version_string()) 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 376, in send_header 
    self.wfile.write("%s: %s\r\n" % (keyword, value)) 
    File "/usr/lib/python2.5/socket.py", line 274, in write 
    self.flush() 
    File "/usr/lib/python2.5/socket.py", line 261, in flush 
    self._sock.sendall(buffer) 
error: (32, 'Broken pipe') 

大部分这些错误似乎不必调用send_header()方法的一个问题阻止所有我写出来是这样的:

self.send_header('Location', long_url) 

所以我很好奇,凡在我的代码,试图陷阱这个IO除外离子...我写的尝试/除了调用每个self.send_header/self.end_headers/self.wfile.write调用?其他错误,我从不时看到是这一个,但不是一定要注意连追这其中的例外:

Traceback (most recent call last): 
    File "/usr/lib/python2.5/SocketServer.py", line 222, in handle_request 
    self.process_request(request, client_address) 
    File "/usr/lib/python2.5/SocketServer.py", line 241, in process_request 
    self.finish_request(request, client_address) 
    File "/usr/lib/python2.5/SocketServer.py", line 254, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/lib/python2.5/SocketServer.py", line 522, in __init__ 
    self.handle() 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 316, in handle 
    self.handle_one_request() 
    File "/usr/lib/python2.5/BaseHTTPServer.py", line 299, in handle_one_request 
    self.raw_requestline = self.rfile.readline() 
    File "/usr/lib/python2.5/socket.py", line 381, in readline 
    data = self._sock.recv(self._rbufsize) 
error: (104, 'Connection reset by peer') 

回答

6

“破管”异常意味着你的代码试图写入套接字/管道另一端已关闭。如果另一端是Web浏览器,则用户可能已经停止了该请求。你可以忽略回溯;它并不表示一个严重的问题。如果你想压制消息,你可以在http_output函数的所有代码周围放一个try ... except块,并且如果你愿意的话记录异常。

此外,如果您希望您的HTTP服务器一次处理多个请求,则需要您的服务器类使用SocketServer.ForkingMixIn和SocketServer.ThreadingMixIn类之一。有关详细信息,请查看SocketServer模块的文档。

添加如下内容:“通过对等连接复位”异常意味着你的代码试图从死套接字读取。如果要抑制回溯,则需要扩展BaseHTTPServer类并重写handle_one_request方法以添加try ... except块。无论如何,您将需要一个新的服务器类来实现先前关于一次处理多个请求的建议。

+0

谢谢!我并不太在意多处理。我很好奇哪个异常实际陷入困境,它只是IOError异常,还是其他东西? 我也怀疑破裂的水管中的错误是从这个系统过着HAProxy的防火墙后面的事实来了。这是我的下一个搜索。 – iandouglas 2011-05-23 17:11:02

+1

套接字模块中的函数引发socket.error。从python 2.6开始,socket.error是IOError的子类([socket module](http://docs.python.org/library/socket.html)的文档)。由于您的目标是2.5(根据回溯中的文件名判断),因此您需要捕获socket.error。 – 2011-05-26 05:24:26

9

这似乎是在SocketServer的一个bug,看到这个链接Python Bug: 14574

修复程序(在Python 2.7对我的作品)是覆盖SocketServer.StreamRequestHandler完成()方法,像这样:

... 
def finish(self,*args,**kw): 
    try: 
    if not self.wfile.closed: 
     self.wfile.flush() 
     self.wfile.close() 
    except socket.error: 
    pass 
    self.rfile.close() 

    #Don't call the base class finish() method as it does the above 
    #return SocketServer.StreamRequestHandler.finish(self) 
+0

感谢Jason的跟进! – iandouglas 2013-01-16 19:49:51

+0

我的解决方案与你的类似,但在'handle()'方法中 – 2017-03-15 16:17:49

3

在我的应用程序,并没有出现在finish()错误,它发生在handle()。此修复捕获broken pipe错误:

class MyHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): 

    ... 

    def handle(self): 
     try: 
      BaseHTTPServer.BaseHTTPRequestHandler.handle(self) 
     except socket.error: 
      pass