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

Posted

技术标签:

【中文标题】使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?【英文标题】:Using RoboSpice is there a way to get the HTTP Error Code out of an exception? 【发布时间】:2013-01-29 15:28:52 【问题描述】:

我正在编写一个使用 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 );

【问题讨论】:

【参考方案1】:

对于那些无法将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。而且我还没有验证是否可以删除任何铸件...

【讨论】:

RetrofitError 是 Retrofit 1.6.1 中定义的类。如果您使用的是 2.x,它可能不再存在。路径:retrofit-1.6.1-sources.jar!/retrofit/RetrofitError.java public class RetrofitError extends RuntimeException ...【参考方案2】:

这比所有其他答案都容易。

对我来说@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()
    

【讨论】:

如何处理多个并发请求?此代码将执行多个身份验证请求,不是吗。 这取决于您对 auth store 的实现。我使用帐户管理器。如果其中一个并发请求得到 401,它会更新 AccountManager 中的令牌,并且所有后续请求都将从此时获得适当的令牌。但我从来没有真正尝试过使用这段代码并发请求【参考方案3】:

使用适用于 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());

【讨论】:

【参考方案4】:

我正在使用带有 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");
    

【讨论】:

【参考方案5】:

我仔细查看了 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");
    

【讨论】:

我在使用equals() 比较状态码和HttpStatus 时遇到了一些不一致的问题。相反,我开始毫无问题地比较它们:exception.getStatusCode().value() == HttpStatus.SC_BAD_REQUEST。希望对您有所帮助。 HttpClientErrorException 无法解析为类型。 我得到一个 HttpResponseException 而不是 HttpClientErrorException 它是特定于 Apache HTTP 客户端后端的,不是吗?

以上是关于使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法从 R 的列中取出异常值?

有没有办法强制 Java VM 立即执行从 JNI 发送的异常?

在@HystrixCommand 回退方法中获取失败异常

有没有办法使用 Video.js 从视频标签中获取当前字幕的文本?

有没有办法在肺癌数据集中使用多类分类(表明肺癌的异常类型)? [关闭]

当自我没有广播交易时,如何使用以太坊客户端从状态恢复异常中获取消息?