14

我正在编写一个使用 RoboSpice 的应用程序。在请求侦听器 onRequestFailure(SpiceException arg0) 中,有没有办法确定错误是由 401 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 );
}
4

5 回答 5

20

我仔细查看了 Spring-Android,似乎 getRestTemplate().getForObject(...) 在发生 401 或任何网络错误时抛出 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");
    }
}
于 2013-02-15T16:21:17.417 回答
2

我正在使用带有 RoboSpice 的 google 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");
    }
于 2013-02-20T11:05:50.183 回答
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。而且我还没有验证是否可以删除任何铸件...

于 2016-01-11T09:46:25.397 回答
0

使用适用于 java 的 google http 客户端,您还可以拦截错误响应,如下所示:

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());
}
于 2013-04-27T03:09:42.027 回答
0

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

对我来说@Scrotos 的回答是有问题的,因为要捕获 401 的重点是向身份验证端点发出请求,然后再次发出主要请求。这样您就只能返回带有所需数据或一些“真实”错误的 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()
    }
于 2014-09-15T10:10:42.083 回答