2013-02-13 12 views
14

Sto scrivendo un'applicazione che utilizza RoboSpice. Nella richiesta listener onRequestFailure (SpiceException arg0) esiste un modo per sapere con certezza che l'errore è stato il risultato di un errore HTTP 401 si è verificato?Utilizzo di RoboSpice esiste un modo per ottenere il codice errore HTTP da un'eccezione?

Ho un servizio di back-end, che restituisce un errore 401 quando un token scade, quando ciò accade, devo richiedere all'utente di reinserire le proprie credenziali.

C'è comunque da sapere che si è verificato in particolare un errore HTTP 401?

Di seguito è riportato un esempio della mia richiesta.

public class LookupRequest extends SpringAndroidSpiceRequest <Product> { 

public String searchText; 
public String searchMode; 

public LookupRequest() { 
    super(Product.class); 
} 

@Override 
public Product loadDataFromNetwork() throws Exception { 
    String url = String.format("%s/Lookup?s=%s&m=%s", Constants.BASE_URL, searchText, searchMode); 
    Ln.d("Calling URL: %s", url); 
    return getRestTemplate().getForObject(url, Product.class); 
} 

risposta

20

Ho guardato oltre Primavera-Android più vicino e sembra getRestTemplate(). GetForObject (...) getta una HttpClientErrorException quando si verifica un 401 o di qualsiasi errore di rete.

Guardando il Robo Spice per dove hanno rilevato quell'eccezione, ho trovato che lo rilevavano in RequestProcessor.java nella funzione processRequest. Passano l'eccezione Spring-Android come il throwable all'interno della SpiceException che eredita dalla classe di eccezioni Java.

Quindi basta fare quanto segue all'interno del RequestListener di RoboSpice per vedere se si tratta di un'eccezione 401 NON AUTORIZZATA.

private class MyRequestListener implements RequestListener<RESULT> { 

    public void onRequestFailure(SpiceException arg0) { 

     if(arg0.getCause() instanceof HttpClientErrorException) 
     { 
      HttpClientErrorException exception = (HttpClientErrorException)arg0.getCause(); 
      if(exception.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) 
      { 
       Ln.d("401 ERROR"); 
      } 
      else 
      { 
       Ln.d("Other Network exception"); 
      } 
     } 
     else if(arg0 instanceof RequestCancelledException) 
     { 
      Ln.d("Cancelled"); 
     } 
     else 
     { 
      Ln.d("Other exception"); 
     } 
    }; 

    public void onRequestSuccess(RESULT result) { 
     Ln.d("Successful request"); 
    } 
} 
+3

Sto riscontrando alcune incoerenze usando 'equals()' per confrontare il codice di stato e 'HttpStatus'. Invece ho iniziato a confrontarli senza problemi: 'exception.getStatusCode(). Value() == HttpStatus.SC_BAD_REQUEST'. Spero possa aiutare. – Moritz

+3

'HttpClientErrorException' non può essere risolto con un tipo. – KarenAnne

+0

Invece di HttpClientErrorException, sto ricevendo una HttpResponseException – kheit

2

Sto usando il client http Google con RoboSpice e ha lo stesso problema, ma era facile da risolvere con request.setThrowExceptionOnExecuteError(false); e controllando il codice di risposta sul conseguente HttpResponse oggetto

EDIT: il codice snippit come richiesto

HttpRequest request = getHttpRequestFactory().buildPostRequest(new GenericUrl(URL), content); 
request.setThrowExceptionOnExecuteError(false); 
HttpResponse response = request.execute(); 

switch(response.getStatusCode()) 
    { 
     case HttpStatusCodes.STATUS_CODE_UNAUTHORIZED: 
      return new MyBaseResponse(responseBody); 
     default: 
      throw new RuntimeException("not implemented yet"); 
    } 
+0

Qualche codice sarebbe benvenuto. :) – Snicolas

+0

done - have edited – Dori

0

con Google client HTTP per Java è anche possibile intercettare risposte di errore in questo modo:

public static class InitIntercept implements 
    HttpRequestInitializer, HttpUnsuccessfulResponseHandler { 

    @Override 
    public boolean handleResponse(
     HttpRequest request, 
     HttpResponse response, 
     boolean retrySupported) throws IOException { 

     if (response.getStatusCode() == HttpStatusCodes.STATUS_CODE_UNAUTHORIZED) { 
      ... 
     } 

     return false; 
    } 

    @Override 
    public void initialize(HttpRequest request) throws IOException { 
     request.setUnsuccessfulResponseHandler(this); 
    } 
} 

e nel tuo GoogleHttpClientSpiceService:

@Override 
public HttpRequestFactory createRequestFactory() { 
    return AndroidHttp 
     .newCompatibleTransport().createRequestFactory(new InitIntercept()); 
} 
0

è ancora più facile rispetto a tutte le altre risposte.

Per me la risposta @Scrotos è stata problematica, perché l'intero punto per il 401 da catturare è di effettuare la richiesta all'autent endpoint e quindi effettuare nuovamente la richiesta primaria. In modo che tu ritorni solo all'interfaccia utente con i dati desiderati o qualche errore "reale". Quindi non dovrebbe essere fatto all'interno del callback, ma piuttosto all'interno di loadDataFromNetwork() stesso.

ho fatto in questo modo:

@Override 
public SubscriptionsContainer loadDataFromNetwork() { 

    //... 

    ResponseEntity<SubscriptionsContainer> response = null; 
    try { 
     response = getRestTemplate().exchange(
     //your request data      
     ); 
    } catch (HttpClientErrorException e) { 
     HttpStatus statusCode = e.getStatusCode(); 
     //check the exception, if it's 401, make call to auth and repeat loadDataFromNetwork() 
    } 
+0

Come si gestiscono richieste multiple simultanee? Questo codice farà più richieste di autorizzazione, non lo farà. – BornToCode

+0

Dipende dalla tua implementazione di auth store. Io uso AccountManager. Se una delle richieste simultanee diventa 401, aggiorna il token all'interno di AccountManager e tutte le richieste successive otterranno un token appropriato da questo punto. Ma non ho mai veramente provato richieste contemporanee con questo codice –

2

Per coloro che non possono risolvere HttpClientErrorException in un tipo, e non riesco a trovare nessuna documentazione in linea, (che sono io), qui è il mio approccio:

Nel mio frammento, qui è il mio ascoltatore:

private final class MyRequestListener extends RequestListener<MyResponse> { 

    @Override 
    public void onRequestFailure(SpiceException spiceException) { 
    super.onRequestFailure(spiceException); 
    if (spiceException instanceof NetworkException) { 
     NetworkException exception = (NetworkException) spiceException; 
     if (exception.getCause() instance RetrofitError) { 
     RetrofitError error = (RetrofitError) exception.getCause(); 
     int httpErrorCode = error.getResponse().getStatus(); 
     // handle the error properly... 
     return; 
     } 
    } 
    // show generic error message 
    } 

} 

Spero che questo forse utile a qualcuno.

Vorrei spostare l'intera clausola if in una funzione statica in modo che possa essere riutilizzata. Basta restituire 0 se l'eccezione non corrisponde. E non ho verificato se uno qualsiasi dei casting possa essere rimosso ...

+0

Che cos'è RetrofitError? puoi pubblicare il tuo codice? – exequielc

+1

RetrofitError è una classe definita in Retrofit 1.6.1. Se stai usando 2.x, potrebbe non esserci più. Percorso: retrofit-1.6.1-sources.jar! /retrofit/RetrofitError.java public class RetrofitError estende RuntimeException {...} –

Problemi correlati