Использование RoboSpice - это способ получить код ошибки HTTP из исключения? - программирование
Подтвердить что ты не робот

Использование RoboSpice - это способ получить код ошибки HTTP из исключения?

Я пишу приложение, которое использует RoboSpice. В запросе listener onRequestFailure (SpiceException arg0) есть ли способ точно знать, что ошибка возникла из-за ошибки 401 HTTP?

У меня есть служба back-end, которая возвращает ошибку 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 );
}
4b9b3361

Ответ 1

Я просмотрел Spring -Android ближе, и кажется getRestTemplate(). getForObject (...) генерирует исключение HttpClientErrorException при возникновении ошибки 401 или любой сетевой ошибки.

Глядя на Robo Spice, где они поймают это исключение, я обнаружил, что они улавливают его в RequestProcessor.java в функции processRequest. Они передают исключение Spring -Android в качестве броски внутри своего SpiceException, которое наследуется от класса исключений Java.

Итак, вы просто делаете следующее внутри своего 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");
    }
}

Ответ 2

Я использую http-клиент google с RoboSpice и имеет ту же проблему, но легко решить с помощью request.setThrowExceptionOnExecuteError(false); и проверить код ответа на результирующий объект HttpResponse

EDIT: фрагмент кода по запросу

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

Ответ 3

Для тех, кто не может разрешить 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, если исключение не совпадает. И я не проверяю, можно ли удалить какое-либо из кастинга...

Ответ 4

С клиентом google 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());
}

Ответ 5

Это еще проще, чем все другие ответы.

Для меня ответ @Scrotos был проблематичным, потому что цель для 401 быть пойманной - сделать запрос конечной точке auth, а затем снова сделать первичный запрос. Чтобы вы только вернулись к пользовательскому интерфейсу с желаемыми данными или некоторой "реальной" ошибкой. Поэтому это не должно быть сделано внутри обратного вызова, а скорее внутри 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 401, make call to auth and repeat loadDataFromNetwork()
    }