Android 使用RoboSpice是否有办法从异常中获取HTTP错误代码?

Android 使用RoboSpice是否有办法从异常中获取HTTP错误代码?,android,http-status-code-401,robospice,Android,Http Status Code 401,Robospice,我正在编写一个使用RoboSpice的应用程序。在请求侦听器onRequestFailure(SpiceException arg0)中,是否有方法确定错误是由401 HTTP错误引起的 我有一个后端服务,当令牌过期时返回401错误,当出现这种情况时,我需要提示用户重新输入他们的凭据 有没有人知道具体发生了401 HTTP错误 下面是我请求的一个例子 public class LookupRequest extends SpringAndroidSpiceRequest <Produ

我正在编写一个使用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 );
}
公共类LookupRequest扩展了SpringAndroidPiceRequest{
公共字符串搜索文本;
公共字符串搜索模式;
公共LookupRequest(){
超级(产品级);
}
@凌驾
公共产品loadDataFromNetwork()引发异常{
字符串url=String.format(“%s/Lookup?s=%s&m=%s”,Constants.BASE\u url,searchText,searchMode);
Ln.d(“调用URL:%s”,URL);
返回getRestTemplate().getForObject(url,Product.class);
}

我查看了Spring Android closer,发现getRestTemplate().getForObject(…)在发生401或任何网络错误时抛出HttpClientErrorException

通过查看Robo Spice,我发现他们在processRequest函数的RequestProcessor.java中捕获了该异常。他们将Spring Android异常作为SpiceException中的可丢弃项传入,SpiceException继承自java exception类

因此,您只需在RoboSpice RequestListener中执行以下操作,以查看它是否是未经授权的异常

    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");
    }
}
私有类MyRequestListener实现RequestListener{
公共void onRequestFailure(异常arg0){
如果(arg0.getCause()实例为HttpClientErrorException)
{
HttpClientErrorException=(HttpClientErrorException)arg0.getCause();
if(exception.getStatusCode().equals(HttpStatus.UNAUTHORIZED))
{
Ln.d(“401错误”);
}
其他的
{
Ln.d(“其他网络例外”);
}
}
else if(请求取消异常的arg0实例)
{
Ln.d(“取消”);
}
其他的
{
Ln.d(“其他例外情况”);
}
};
public void onRequestSuccess(结果){
Ln.d(“成功请求”);
}
}

我正在将google http客户端与RoboSpice一起使用,并且有相同的问题,但通过
请求很容易解决。setThroweExceptionOnExecuteError(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");
    }

使用google http client for 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);
    }
}
在您的GoogleHttpClientSpices服务中:

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

这比所有其他答案都要简单

对我来说@Scrotos的答案是有问题的,因为401被捕获的全部要点是向auth endpoint发出请求,然后再次发出主请求。因此,您只能返回带有所需数据或某些“真实”错误的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()
    }
@覆盖
公共订阅容器loadDataFromNetwork(){
//...
ResponseEntity response=null;
试一试{
响应=getRestTemplate().exchange(
//您的请求数据
);
}捕获(HttpClientErrorE异常){
HttpStatus statusCode=e.getStatusCode();
//检查异常,如果是401,则调用auth并重复loadDataFromNetwork()
}

对于那些无法将
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
  }

}
私有最终类MyRequestListener扩展了RequestListener{
@凌驾
公共void onRequestFailure(SpiceException){
super.onRequestFailure(异常);
if(网络异常的异常实例){
NetworkException异常=(NetworkException)异常;
if(exception.getCause()实例错误){
RefundationError=(RefundationError)异常。getCause();
int-httpErrorCode=error.getResponse().getStatus();
//正确处理错误。。。
返回;
}
}
//显示一般错误消息
}
}
希望这可能对某人有所帮助


我会将整个
if
子句移动到一个静态函数中,以便重用。如果异常不匹配,只需返回0。我还没有验证是否可以删除任何强制转换…

我使用
equals()时遇到一些不一致的情况
比较状态代码和
HttpStatus
。相反,我开始比较它们,因此没有问题:
exception.getStatusCode().value()==HttpStatus.SC_BAD_REQUEST
。希望有帮助。
HttpClientErrorException
无法解析为类型。我得到的不是HttpClientErrorException,而是HttpResponseException,它是特定于Apache HTTP客户端后端的,不是吗?如何处理多个并发请求?此代码将执行多个身份验证请求,不是吗。这取决于您对auth store的实现。我使用AccountManager。如果其中一个并发请求获得401,它将更新AccountManager内的令牌,并且所有后续请求将从此点获得正确的令牌。但我从未使用此代码尝试过并发请求。Reformation Error是在Reformation 1.6.1中定义的类。如果您是使用2.x,它可能不再存在了