2013-02-13 5 views
14

Ich schreibe eine Anwendung, die RoboSpice verwendet. Gibt es in dem Request-Listener onRequestFailure (SpiceException arg0) eine Möglichkeit, sicher zu wissen, dass der Fehler das Ergebnis eines 401-HTTP-Fehlers war?Mit RoboSpice gibt es eine Möglichkeit, den HTTP-Fehlercode aus einer Ausnahme zu bekommen?

Ich habe einen Back-End-Dienst, der einen Fehler 401 zurückgibt, wenn ein Token abläuft, wenn dies auftritt, muss ich den Benutzer auffordern, ihre Anmeldeinformationen erneut einzugeben.

Gibt es trotzdem zu wissen, dass ein 401 HTTP-Fehler speziell aufgetreten ist?

Unten ist ein Beispiel für meine Anfrage.

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); 
} 

Antwort

20

Ich schaute über Feder Android näher und es scheint getRestTemplate(). GetForObject (...) eine HttpClientErrorException wirft, wenn ein 401 oder Netzwerk-Fehler auftritt.

Mit Blick auf den Robo Spice für, wo sie die Ausnahme fangen, fand ich sie in RequestProcessor.java in der ProcessRequest-Funktion abfangen. Sie übergeben die Spring-Android-Ausnahme in ihrer SpiceException als thrown, die von der Java-Ausnahmeklasse erbt.

Also machen Sie einfach folgendes in Ihrem RoboSpice RequestListener um zu sehen, ob es eine 401 UNAUTHORIZED Ausnahme ist.

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

Ich habe einige Inkonsistenzen durch Verwendung von 'equals()', um den Statuscode und 'HttpStatus' zu vergleichen. Stattdessen habe ich damit begonnen, sie ohne Probleme zu vergleichen: 'exception.getStatusCode(). Value() == HttpStatus.SC_BAD_REQUEST'. Ich hoffe, das hilft. – Moritz

+3

'HttpClientErrorException' kann nicht in einen Typ aufgelöst werden. – KarenAnne

+0

Anstelle von HttpClientErrorException erhalte ich eine HttpResponseException – kheit

2

Ich bin mit dem Google-http-Client mit RoboSpice und habe das gleiche Problem, aber war einfach mit request.setThrowExceptionOnExecuteError(false); und Überprüfung des Antwortcode auf dem resultierenden HttpResponse Objekt

EDIT zu lösen: der Code snippit als

angefordert
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

Einige Code wäre willkommen. :) – Snicolas

+0

fertig - bearbeitet haben – Dori

0

mit google http-Client für Java wie Sie können auch Antworten abfangen Fehler so:

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); 
    } 
} 

und in Ihrem GoogleHttpClientSpiceService:

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

Es ist sogar einfacher als alle anderen Antworten.

Für mich @Scrotos Antwort war problematisch, weil der ganze Punkt für die 401 abgefangen werden soll, um die Anfrage an auth Endpunkt und dann die primäre Anfrage erneut zu machen. Damit kehren Sie nur mit den gewünschten Daten oder einem "echten" Fehler zur UI zurück. Es sollte also nicht innerhalb des Callbacks gemacht werden, sondern innerhalb von loadDataFromNetwork() selbst.

Ich habe es so gemacht:

@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

Wie gehen Sie mit mehreren gleichzeitige Anfrage? Dieser Code wird mehrere Authentifizierungsanfragen ausführen, nicht wahr? – BornToCode

+0

Es hängt von Ihrer Implementierung von Auth-Speicher ab. Ich benutze AccountManager. Wenn eine der gleichzeitigen Anfragen 401 erhält, aktualisiert sie das Token in AccountManager und alle nachfolgenden Anfragen erhalten von diesem Punkt ein richtiges Token. Aber ich habe nie wirklich gleichzeitige Anfragen mit diesem Code versucht –

2

Für diejenigen, die nicht HttpClientErrorException in eine Art lösen können, und kann keine Dokumentationen nicht online finden, (das bin ich), hier ist mein Ansatz:

In meinem Fragmente, hier sind meine Zuhörer:

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 
    } 

} 

Hope this vielleicht hilfreich für jemanden.

Ich würde die ganze if Klausel in eine statische Funktion verschieben, so dass es wiederverwendet werden kann. Geben Sie einfach 0 zurück, wenn die Ausnahme nicht übereinstimmt. Und ich habe nicht überprüft, ob irgendein Casting entfernt werden kann ...

+0

Was ist RetrofitError? Kannst du deinen Code posten? – exequielc

+1

RetrofitError ist eine in Retrofit 1.6.1 definierte Klasse. Wenn Sie 2.x verwenden, ist es möglicherweise nicht mehr da. Pfad: retrofit-1.6.1-sources.jar! /retrofit/RetrofitError.java Öffentliche Klasse RetrofitError erweitert RuntimeException {...} –