Intereting Posts
Некоторые параметры функции с именем arg0, arg1 и т. Д. После компиляции JAR-библиотеки Зачем использовать ContentProvider.getType () для получения типа MIME? Android совместно с Picasso InAppBilling активность и финиш () Возможно ли установить приложение через adb, но все равно получать обновления в Google Market? Как я читаю / записываю шестнадцатеричные байты из потока ввода / вывода в BluetoothChat? Android LinearLayout с несколькими строками Как использовать View.OnTouchListener вместо onClick Превышен дневной лимит неиспользуемого использования. Для продолжения использования требуется регистрация Как я могу использовать библиотеку модернизации с помощью progressbar? EGL работает на Linux, но не на Android Скрыть разделитель, не скрывая childDivider на ExpandableListView Значок hdpi ldpi mdpi / разрешение меню Как я могу отправить SMS из BroadcastReceiver и проверить его статус? Что onEndReachedThreshold действительно означает в

Код состояния HTTP в Android Volley, когда error.networkResponse имеет значение null

Я использую Google Volley на платформе Android. У меня возникла проблема, в которой параметр error в onErrorResponse возвращает нулевую networkResponse Для используемого API RESTful мне нужно определить код состояния Http, который часто приходит как 401 (SC_UNAUTHORIZED) или 500 (SC_INTERNAL_SERVER_ERROR), и я Может иногда проверять через:

 final int httpStatusCode = error.networkResponse.statusCode; if(networkResponse == HttpStatus.SC_UNAUTHORIZED) { // Http status code 401: Unauthorized. } 

Это вызывает networkResponse NullPointerException потому что networkResponse равно null.

Как определить код состояния Http в функции onErrorResponse ?

Или, как я могу гарантировать, что error.networkResponse не имеет значения null в onErrorResponse ?

Или, как я могу гарантировать, что error.networkResponse не имеет значения null в onErrorResponse?

Моя первая мысль состояла в том, чтобы проверить, является ли объект нулевым.

 @Override public void onErrorResponse(VolleyError error) { NetworkResponse networkResponse = error.networkResponse; if (networkResponse != null && networkResponse.statusCode == HttpStatus.SC_UNAUTHORIZED) { // HTTP Status Code: 401 Unauthorized } } 

Кроме того, вы также можете попробовать захватить код состояния, расширив класс Request и переопределив parseNetworkResponse .

Например, если расширение абстрактного Request<T> class

 public class GsonRequest<T> extends Request<T> { ... private int mStatusCode; public int getStatusCode() { return mStatusCode; } ... @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; try { Log.d(TAG, "[raw json]: " + (new String(response.data))); Gson gson = new Gson(); String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(gson.fromJson(json, mClazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } ... } 

Или, если вы используете один из классов панели инструментов, которые уже расширяют абстрактный Request<T> и вы не хотите parseNetworkResponse(NetworkResponse networkResponse) реализацию для parseNetworkResponse(NetworkResponse networkResponse) , продолжайте переопределять метод, но верните реализацию super.parseNetworkResponse(networkResponse) через super.parseNetworkResponse(networkResponse)

Например, StringResponse

 public class MyStringRequest extends StringRequest { private int mStatusCode; public MyStringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, listener, errorListener); } public int getStatusCode() { return mStatusCode; } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; return super.parseNetworkResponse(response); } } 

Применение:

 public class myClazz extends FragmentActivity { private Request mMyRequest; ... public void makeNetworkCall() { mMyRequest = new MyNetworkRequest( Method.GET, BASE_URL + Endpoint.USER, new Listener<String>() { @Override public void onResponse(String response) { // Success } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (mMyRequest.getStatusCode() == 401) { // HTTP Status Code: 401 Unauthorized } } }); MyVolley.getRequestQueue().add(request); } 

Конечно, опция переопределения метода inline также доступна

 public class MyClazz extends FragmentActivity { private int mStatusCode; ... public void makeNetworkCall() { StringRequest request = new StringRequest( Method.GET, BASE_URL + Endpoint.USER, new Listener<String>() { @Override public void onResponse(String response) { // Success } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (mStatusCode == 401) { // HTTP Status Code: 401 Unauthorized } } }) { @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { mStatusCode = response.statusCode; return super.parseNetworkResponse(response); } }; MyVolley.getRequestQueue.add(request); } 

Обновить:
HttpStatus . HttpURLConnection этого используйте HttpURLConnection . См. Ссылку .

401 Не поддерживается волейболом

Оказывается, невозможно гарантировать, что error.networkResponse не имеет значения null, не изменяя код Google Volley из-за ошибки во Volley, которая NoConnectionError исключение NoConnectionError для кода состояния Http 401 ( HttpStatus.SC_UNAUTHORIZED ) в BasicNetwork.java (134) Перед установкой значения networkResponse .

Работа-Around

Вместо того, чтобы фиксировать код Volley, нашим решением в этом случае было изменение API веб-службы для отправки Http Error Code 403 ( HttpStatus.SC_FORBIDDEN ) для конкретного конкретного случая.

Для этого кода состояния Http значение error.networkResponse равно null в обработчике ошибок Volley: public void onErrorResponse(VolleyError error) . И error.networkResponse.httpStatusCode корректно возвращает HttpStatus.SC_FORBIDDEN .

Другие-предложения

Предложение Rperryng о расширении класса Request<T> возможно, обеспечило решение и является творческой и отличной идеей. Большое спасибо за подробный пример. Я нашел оптимальное решение для нашего случая – использовать обход, потому что нам посчастливилось управлять API веб-сервисов.

Я мог бы выбрать фиксацию кода Volley в одном месте в BasicNetwork.java, если бы у меня не было доступа к простому изменению на сервере.

Волейбол поддерживает HTTP 401 Несанкционированный отклик. Но этот ответ ДОЛЖЕН включать поле заголовка «WWW-Authenticate».

Без этого заголовка ответ 401 вызывает "com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found" ошибка "com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found" .

Для получения более подробной информации: https://stackoverflow.com/a/25556453/860189

Если вы потребляете сторонние API и не имеете права изменять заголовок ответа, вы можете рассмотреть возможность реализовать свой собственный HttpStack из-за этого исключения, выброшенного из HurlStack. Или лучше, используйте OkHttpStack как HttpStack.

error.networkResponse будет null , если устройство не имеет сетевого подключения (вы можете это доказать, включив режим самолета). Посмотрите на соответствующий фрагмент кода из библиотеки Volley.

Затем вы должны проверить, если ошибка является экземпляром NoConnectionError , прежде чем искать networkResponse . Я не могу согласиться, что ошибка 401 не поддерживается Volley, я ее протестировал и получил networkResponse объект networkResponse с кодом состояния 401. Посмотрите на соответствующий код здесь .

Ответ сети можно получить в следующем формате

 NetworkResponse response = error.networkResponse; if(response != null && response.data != null){ switch(response.statusCode){ case 403: json = new String(response.data); json = trimMessage(json, "error"); if(json != null) displayMessage(json); break; } } 

Вот как я проверяю ошибку и grep.

  // TimeoutError => most likely server is down or network is down. Log.e(TAG, "TimeoutError: " + (e instanceof TimeoutError)); Log.e(TAG, "NoConnectionError: " + (e instanceof NoConnectionError)); /*if(error.getCause() instanceof UnknownHostException || error.getCause() instanceof EOFException ) { errorMsg = resources.getString(R.string.net_error_connect_network); } else { if(error.getCause().toString().contains("Network is unreachable")) { errorMsg = resources.getString(R.string.net_error_no_network); } else { errorMsg = resources.getString(R.string.net_error_connect_network); } }*/ Log.e(TAG, "NetworkError: " + (e instanceof NetworkError)); Log.e(TAG, "AuthFailureError: " + (e instanceof AuthFailureError)); Log.e(TAG, "ServerError: " + (e instanceof ServerError)); //error.networkResponse.statusCode // inform dev Log.e(TAG, "ParseError: " + (e instanceof ParseError)); //error.getCause() instanceof JsonSyntaxException Log.e(TAG, "NullPointerException: " + (e.getCause() instanceof NullPointerException)); if (e.networkResponse != null) { // 401 => login again Log.e(TAG, String.valueOf(e.networkResponse.statusCode)); if (e.networkResponse.data != null) { // most likely JSONString Log.e(TAG, new String(e.networkResponse.data, StandardCharsets.UTF_8)); Toast.makeText(getApplicationContext(), new String(e.networkResponse.data, StandardCharsets.UTF_8), Toast.LENGTH_LONG).show(); } } else if (e.getMessage() == null) { Log.e(TAG, "e.getMessage"); Log.e(TAG, "" + e.getMessage()); if (e.getMessage() != null && e.getMessage() != "") Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show(); else Toast.makeText(getApplicationContext(), "could not reach server", Toast.LENGTH_LONG).show(); } else if (e.getCause() != null) { Log.e(TAG, "e.getCause"); Log.e(TAG, "" + e.getCause().getMessage()); if (e.getCause().getMessage() != null && e.getCause().getMessage() != "") Toast.makeText(getApplicationContext(), e.getCause().getMessage(), Toast.LENGTH_LONG).show(); else Toast.makeText(getApplicationContext(), "could not reach server", Toast.LENGTH_LONG).show(); } 

Я обрабатываю эту проблему вручную:

  1. Загрузите библиотеку Volley из github и добавьте в проект AndroidStudio

  2. Перейдите в com.android.volley.toolbox.HurlStack class

  3. Найти setConnectionParametersForRequest(connection, request); Строка внутри метода performRequest

  4. И, наконец, добавьте эти коды из setConnectionParametersForRequest(connection, request); линия :

 // for avoiding this exception : No authentication challenges found try { connection.getResponseCode(); } catch (IOException e) { e.printStackTrace(); }