Используя RoboSpice, есть ли способ получить код ошибки HTTP из исключения?
Я пишу приложение, которое использует 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 );
}
5 ответов
Я посмотрел на 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");
}
}
Я использую HTTP-клиент Google с RoboSpice, и у меня возникла та же проблема, но ее было легко решить 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");
}
Для тех, кто не может решить 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, если исключение не совпадает. И я не проверяю, можно ли удалить кастинг...
С помощью HTTP-клиента Google для 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());
}
Это даже проще, чем все остальные ответы.
Для меня ответ @Scrotos был проблематичным, потому что весь смысл для 401, который должен быть пойман, состоит в том, чтобы сделать запрос к конечной точке аутентификации и затем сделать основной запрос снова. Так что вы вернетесь в пользовательский интерфейс только с желаемыми данными или какой-то "реальной" ошибкой. Так что это не должно быть сделано внутри обратного вызова, а скорее внутри 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()
}