2010-08-13 11 views
5

Abbiamo due applicazioni in esecuzione su Google App Engine. App1 effettua richieste a app2 come utente autenticato. L'autenticazione funziona richiedendo un token di autenticazione da Google ClientLogin che viene scambiato per un cookie. Il cookie viene quindi utilizzato per richieste successive (come descritto here). App1 esegue il codice seguente:Errore di applicazione intermittente DownloadError 2 su Google App Engine

class AuthConnection: 

    def __init__(self):    
     self.cookie_jar = cookielib.CookieJar()  
     self.opener = urllib2.OpenerDirector() 
     self.opener.add_handler(urllib2.ProxyHandler()) 
     self.opener.add_handler(urllib2.UnknownHandler()) 
     self.opener.add_handler(urllib2.HTTPHandler()) 
     self.opener.add_handler(urllib2.HTTPRedirectHandler()) 
     self.opener.add_handler(urllib2.HTTPDefaultErrorHandler()) 
     self.opener.add_handler(urllib2.HTTPSHandler()) 
     self.opener.add_handler(urllib2.HTTPErrorProcessor()) 
     self.opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar)) 
     self.headers = {'User-Agent': 'Mozilla/5.0 (Windows; U; ' +\ 
             'Windows NT 6.1; en-US; rv:1.9.1.2) ' +\ 
             'Gecko/20090729 Firefox/3.5.2 ' +\ 
             '(.NET CLR 3.5.30729)' 
         } 

    def fetch(self, url, method, payload=None): 
     self.__updateJar(url) 
     request = urllib2.Request(url) 
     request.get_method = lambda: method 
     for key, value in self.headers.iteritems(): 
      request.add_header(key, value) 
     response = self.opener.open(request) 
     return response.read() 

    def __updateJar(self, url): 

     cache = memcache.Client() 
     cookie = cache.get('auth_cookie') 

     if cookie: 
      self.cookie_jar.set_cookie(cookie) 
     else: 
      cookie = self.__retrieveCookie(url=url) 
      cache.set('auth_cookie', cookie, 5000) 


    def __getCookie(self, url): 
     auth_url = 'https://www.google.com/accounts/ClientLogin' 
     auth_data = urllib.urlencode({'Email': USER_NAME, 
             'Passwd': PASSPHRASE, 
             'service': 'ah', 
             'source': 'app1', 
             'accountType': 'HOSTED_OR_GOOGLE' }) 
     auth_request = urllib2.Request(auth_url, data=auth_data) 
     auth_response_body = self.opener.open(auth_request).read() 
     auth_response_dict = dict(x.split('=') 
       for x in auth_response_body.split('\n') if x) 
     cookie_args = {} 
     cookie_args['continue'] = url 
     cookie_args['auth'] = auth_response_dict['Auth'] 
     cookie_url = 'https://%s/_ah/login?%s' %\ 
       ('app2.appspot.com', (urllib.urlencode(cookie_args))) 
     cookie_request = urllib2.Request(cookie_url) 

     for key, value in self.headers.iteritems(): 
      cookie_request.add_header(key, value) 

     try: 
      self.opener.open(cookie_request) 
     except: 
      pass 

     for cookie in self.cookie_jar:       
      if cookie.domain == 'app2domain': 
       return cookie 

Per il 10-30% delle richieste di un downloadError è sollevato:

Error fetching https://app2/Resource 
Traceback (most recent call last): 
    File "/base/data/home/apps/app1/5.344034030246386521/source/main/connection/authenticate.py", line 112, in fetch 
    response = self.opener.open(request) 
    File "/base/python_runtime/python_dist/lib/python2.5/urllib2.py", line 381, in open 
    response = self._open(req, data) 
    File "/base/python_runtime/python_dist/lib/python2.5/urllib2.py", line 399, in _open 
    '_open', req) 
    File "/base/python_runtime/python_dist/lib/python2.5/urllib2.py", line 360, in _call_chain 
    result = func(*args) 
    File "/base/python_runtime/python_dist/lib/python2.5/urllib2.py", line 1115, in https_open 
    return self.do_open(httplib.HTTPSConnection, req) 
    File "/base/python_runtime/python_dist/lib/python2.5/urllib2.py", line 1080, in do_open 
    r = h.getresponse() 
    File "/base/python_runtime/python_dist/lib/python2.5/httplib.py", line 197, in getresponse 
    self._allow_truncated, self._follow_redirects) 
    File "/base/data/home/apps/app1/5.344034030246386521/source/main/connection/monkeypatch_urlfetch_deadline.py", line 18, in new_fetch 
    follow_redirects, deadline, *args, **kwargs) 
    File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 241, in fetch 
    return rpc.get_result() 
    File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 501, in get_result 
    return self.__get_result_hook(self) 
    File "/base/python_runtime/python_lib/versions/1/google/appengine/api/urlfetch.py", line 325, in _get_fetch_result 
    raise DownloadError(str(err)) 
DownloadError: ApplicationError: 2 

I registri di richiesta per app2 (il "server") sembrano bene, come previsto (secondo i documenti DownloadError viene sollevato solo se non ci sono state risposte HTTP valide).

Perché viene sollevata l'eccezione?

risposta

3

vedono questo: http://bitbucket.org/guilin/gae-rproxy/src/tip/gae_rproxy/niceurllib.py

a causa di urllib e di default urllib2 per gestire il codice HTTP 302, e automaticamente reindirizzare a ciò che il server ha detto che. Ma quando reindirizza non contiene il cookie che il server ha detto.

ad esempio:

  1. richiesta urllib2 // server/login
  2. server di risposta 302, // server/profilo, set-cookie: session-id: xxxx
  3. richiesta urllib2 // server/profilo
  4. risposta del server errore di accesso o 500 errore causa non trovato ID di sessione .
  5. errore urllib2 tiro

quindi, non v'è alcuna possibilità per voi di impostare dei cookie.

self.opener.add_handler (urllib2.HTTPRedirectHandler())

Credo che si dovrebbe rimuovere questa riga e aggiungere la tua HTTPRedirectHandler che errore neighter tiro né automaticamente reindirizzare, basta restituire il codice HTTP e le intestazioni, in modo da avere la possibilità di impostare cookie.