2013-02-13 64 views
14

我在写一个使用RoboSpice的应用程序。在请求监听器onRequestFailure(SpiceException arg0)中有没有一种方法可以确定错误是由于发生了401 HTTP错误?使用RoboSpice有没有办法从异常中获取HTTP错误代码?

我有一个后端服务,当令牌到期时返回401错误,当发生这种情况时,我需要提示用户重新输入他们的凭据。

有无论如何知道专门发生了401 HTTP错误?

下面是我的请求的一个例子。

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

回答

20

我看着春的Android接近,似乎在一个401或任何网络故障发生getRestTemplate()。getForObject(...)抛出一个HttpClientErrorException。

看着Robo Spice找到那个异常的地方,我发现它们在processRequest函数的RequestProcessor.java中捕获它。他们将Spring-Android异常作为继承自Java异常类的SpiceException中的throwable传递。

因此,您只需在RoboSpice RequestListener中执行以下操作,查看它是否为401 UNAUTHORIZED异常。

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

我使用equals()来比较状态码和'HttpStatus',我遇到了一些不一致之处。相反,我开始比较它们,因此没有任何问题:'exception.getStatusCode()。value()== HttpStatus.SC_BAD_REQUEST'。希望有所帮助。 – Moritz 2013-06-17 11:33:38

+3

无法将HttpClientErrorException解析为类型。 – KarenAnne 2014-02-18 06:55:45

+0

而不是HttpClientErrorException,我得到一个HttpResponseException – kheit 2014-08-06 16:29:45

2

我使用与RoboSpice谷歌的HTTP客户端,并且具有相同的问题,但很容易与request.setThrowExceptionOnExecuteError(false);解决,并检查所产生的HttpResponse对象上的响应代码

编辑:根据要求

的代码片段
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

一些代码将受到欢迎。 :) – Snicolas 2013-02-26 21:57:12

+0

完成 - 已编辑 – Dori 2013-02-27 09:06:26

0

与谷歌的HTTP客户端的Java,你也可以像这样拦截错误响应:

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

,并在您GoogleHttpClientSpiceService:

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

它比所有其他的答案更容易。

对于我来说@Scrotos的回答是有问题的,因为要捕获401的全部要点是请求auth端点,然后再次提出主要请求。因此,您只能返回到所需的数据或一些“真正的”错误的UI。 所以它不应该在回调内完成,而应该在loadDataFromNetwork()本身。

我已经做到了这种方式:

@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

你如何处理多个并发请求?此代码将执行多个授权请求,不是吗。 – BornToCode 2014-12-10 13:56:08

+0

这取决于您的身份验证存储的实施。我使用AccountManager。如果其中一个并发请求获得401,它将更新AccountManager内的令牌,并且所有后续请求都会从此处获得适当的令牌。但我从来没有真正尝试使用此代码的并发请求 – 2014-12-10 14:06:25

2

对于那些谁也无法解决HttpClientErrorException成一个类型,而不能在网上找到任何文档,(就是我),这里是我的方法:

在我的片段,这是我的听众:

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 
    } 

} 

希望这也许有帮助的人。

我会将整个if子句移到一个静态函数中,以便它可以重用。如果异常不匹配,则返回0。我没有验证是否有任何铸件可以被删除...

+0

什么是RetrofitError?你可以发布你的代码吗? – exequielc 2016-07-29 11:54:54

+1

RetrofitError是在Retrofit 1.6.1中定义的类。如果你使用2.x,它可能不在那里了。路径:retrofit-1.6.1-sources.jar!/retrofit/RetrofitError.java public class RetrofitError extends RuntimeException {...} – 2016-07-31 09:06:10

相关问题