Question

Je construis un moteur de traducteur URL court en Python et je vois une tonne d'erreurs "tuyaux cassées", et je suis curieux de la piéger mieux lors de l'utilisation des classes de basehttpServer.Ce n'est pas le code entier, mais vous donne une idée de ce que je fais jusqu'à présent:

    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()

Le code lui-même fonctionne bien, mais a commencé à jeter des erreurs presque immédiatement lors de la production:

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')

La majeure partie de ces erreurs semble découler d'avoir un problème d'appeler la méthode Send_header () où tout ce que j'écris, c'est ceci:

self.send_header('Location', long_url)

Je suis donc curieux où dans mon code pour essayer de piéger pour cette exception IO ... Dois-je écrire essayer / sauf des appels autour de chacun des appels Self.Send_header / Self.end_headers / Self.wfile.Write appels?L'autre erreur que je vois de temps en temps est celle-ci, mais je ne sais pas quelle exception à regarder même de l'attraper:

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')

Était-ce utile?

La solution

The "broken pipe" exception means that your code tried to write to a socket/pipe which the other end has closed. If the other end is a web browser, the user could have stopped the request. You can ignore the traceback; it does not indicate a serious problem. If you want to suppress the message, you can put a try ... except block around all of the code in your http_output function, and log the exception if you like.

Additionally, if you want your HTTP server to process more than one request at a time, you need your server class to use one of the SocketServer.ForkingMixIn and SocketServer.ThreadingMixIn classes. Check the documentation of the SocketServer module for details.

Add: The "connection reset by peer" exception means that your code tried to read from a dead socket. If you want to suppress the traceback, you will need to extend the BaseHTTPServer class and override the handle_one_request method to add a try ... except block. You will need a new server class anyway, to implement the earlier suggestion about processing more than one request at a time.

Autres conseils

This appears to be a bug in SocketServer, see this link Python Bug: 14574

A fix (works for me in Python 2.7) is to override the SocketServer.StreamRequestHandler finish() method, something like this:

...
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)

In my application, the error didn't occur in finish(), it occurred in handle(). This fix catches the broken pipe errors:

class MyHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    ...

    def handle(self):
        try:
            BaseHTTPServer.BaseHTTPRequestHandler.handle(self)
        except socket.error:
            pass
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top