【问题标题】:Using RoboSpice is there a way to get the HTTP Error Code out of an exception?使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?
【发布时间】: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 );
}

【问题讨论】:

    标签: android http-status-code-401 robospice


    【解决方案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 客户端后端的,不是吗?
        猜你喜欢
        • 2018-06-17
        • 1970-01-01
        • 2023-04-09
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-27
        相关资源
        最近更新 更多