Código de estado Http en Android Volley cuando se produce un error.networkResponse es nulo


Estoy usando Google Volley en la plataforma Android. Estoy teniendo un problema en el que el parámetro error en onErrorResponse devuelve un null networkResponse Para la API RESTful que estoy usando, necesito determinar el Código de estado Http que a menudo llega como 401 (SC_UNAUTHORIZED) o 500 (SC_INTERNAL_SERVER_ERROR), y ocasionalmente puedo verificar a través de:

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

Esto arroja un NullPointerException porque networkResponse es nulo.

¿Cómo puedo determinar el código de estado Http en la función onErrorResponse?

O, ¿cómo puede Me aseguro de que error.networkResponse no es nulo en onErrorResponse?

Author: Nijraj Gelani, 2014-04-09

8 answers

O, ¿cómo puedo asegurar el error.networkResponse no es nulo en ¿Una respuesta incorrecta?

Mi primer pensamiento sería comprobar si el objeto es null.

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

Alternativamente, también puede intentar obtener el Código de estado extendiendo la clase Request y sobrescribiendo parseNetworkResponse.

Por ejemplo, si se extiende la clase abstracta Request<T>

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

O, si está utilizando una de las clases toolbox que ya extienden la clase abstract Request<T> y no desea confundir la implementación para parseNetworkResponse(NetworkResponse networkResponse), continúe sobrescribiendo el método pero devuelva la implementación del super a través de super.parseNetworkResponse(networkResponse)

Por ejemplo 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);
    }
}

Uso:

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

Por supuesto, la opción para anular el método inline también está disponible

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

Actualizar:
HttpStatus está En desuso. Use HttpURLConnection en su lugar. Véase Enlace .

 70
Author: rperryng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:26

401 No soportado por Volley

Resulta que es imposible garantizar ese error.networkResponse no es nulo sin modificar el código de Google Volley debido a un error en Volley que lanza la Excepción NoConnectionError para el Código de estado Http 401 (HttpStatus.SC_UNAUTHORIZED) en BasicNetwork.java (134)antes de establecer el valor de networkResponse.

Trabajo alrededor

En lugar de arreglar el código Volley, nuestra solución en este caso fue modificar la API de Servicio Web para enviar el código de error Http 403 (HttpStatus.SC_FORBIDDEN) para el caso particular en cuestión.

Para este código de estado Http, el valor de error.networkResponse no es nulo en el controlador de errores de Volea: public void onErrorResponse(VolleyError error). Y, error.networkResponse.httpStatusCode devuelve correctamente HttpStatus.SC_FORBIDDEN.

Otros-Sugerencias

La sugerencia de Rperryng de extender la clase Request<T> puede haber proporcionado una solución, y es una idea creativa y excelente. Muchas gracias por el ejemplo detallado. He encontrado la solución óptima para nuestro caso es utilizar la solución alternativa porque somos lo suficientemente afortunados de tener control de la API de servicios web.

Podría optar por arreglar el código Volley en una ubicación dentro de BasicNetwork.java si no tenía acceso a hacer un simple cambio en el servidor.

 25
Author: David Manpearl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-18 22:21:09

Volley soporta respuesta no autorizada HTTP 401. Pero esta respuesta DEBE incluir el campo de encabezado "WWW-Authenticate".

Sin este encabezado, la respuesta 401 causa un error "com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found".

Para más detalles : https://stackoverflow.com/a/25556453/860189

Si consume API de terceros y no tiene derecho a cambiar el encabezado de la respuesta, puede considerar implementar su propio HttpStack debido a esta excepción lanzada desde HurlStack. O mejor, utilice OkHttpStack como un HttpStack.

 5
Author: tolpp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:21

El error.networkResponse será null, si el dispositivo no tiene conexión de red (puede probar esto activando el modo avión). Mira el correspondiente fragmento de código de la biblioteca Volley.

Tienes que comprobar entonces, si el error es una instancia de la NoConnectionError, antes de buscar la networkResponse. No puedo estar de acuerdo, que el error 401 no es compatible con Volley, lo probé y obtuve un objeto networkResponse no nulo con el código de estado 401. Mira el código correspondiente aquí.

 3
Author: artkoenig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-13 10:05:09

La respuesta de la red se puede recibir en el siguiente formato

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;
                    }
                }
 2
Author: Uday Nayak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 12:57:43

Puede modificar performRequest me(toolbox/BasicNetwork) de la biblioteca volley.java) para capturar la respuesta no autorizada 401. (Este código modificado también resolverá el problema de redirección http-> https de volley)

 @Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();
    while (true) {
        HttpResponse httpResponse = null;
        byte[] responseContents = null;
        Map<String, String> responseHeaders = Collections.emptyMap();
        try {
            // Gather headers.
            Map<String, String> headers = new HashMap<String, String>();
            addCacheHeaders(headers, request.getCacheEntry());
            httpResponse = mHttpStack.performRequest(request, headers);
            StatusLine statusLine = httpResponse.getStatusLine();
            int statusCode = statusLine.getStatusCode();

            responseHeaders = convertHeaders(httpResponse.getAllHeaders());
            // Handle cache validation.
            if (statusCode == HttpStatus.SC_NOT_MODIFIED) {

                Entry entry = request.getCacheEntry();
                if (entry == null) {
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                            responseHeaders, true,
                            SystemClock.elapsedRealtime() - requestStart);
                }

                // A HTTP 304 response does not have all header fields. We
                // have to use the header fields from the cache entry plus
                // the new ones from the response.
                // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
                entry.responseHeaders.putAll(responseHeaders);
                return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                        entry.responseHeaders, true,
                        SystemClock.elapsedRealtime() - requestStart);
            }

            // Handle moved resources
            if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                String newUrl = responseHeaders.get("Location");
                request.setUrl(newUrl);
            }



            // Some responses such as 204s do not have content.  We must check.
            if (httpResponse.getEntity() != null) {
                responseContents = entityToBytes(httpResponse.getEntity());
            } else {
                // Add 0 byte response as a way of honestly representing a
                // no-content request.
                responseContents = new byte[0];
            }

            // if the request is slow, log it.
            long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
            logSlowRequests(requestLifetime, request, responseContents, statusLine);

            if (statusCode < 200 || statusCode > 299) {
                throw new IOException();
            }
            return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                    SystemClock.elapsedRealtime() - requestStart);
        } catch (SocketTimeoutException e) {
            attemptRetryOnException("socket", request, new TimeoutError());
        } catch (ConnectTimeoutException e) {
            attemptRetryOnException("connection", request, new TimeoutError());
        } catch (MalformedURLException e) {
            throw new RuntimeException("Bad URL " + request.getUrl(), e);
        } catch (IOException e) {
            int statusCode = 0;
            NetworkResponse networkResponse = null;
            if (httpResponse != null) {
                statusCode = httpResponse.getStatusLine().getStatusCode();
            } else {
                throw new NoConnectionError(e);
            }
            if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
                    statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                VolleyLog.e("Request at %s has been redirected to %s", request.getUrl(), request.getUrl());
            } else {
                VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                if (statusCode==HttpStatus.SC_FORBIDDEN) {
                    throw new VolleyError("403");
                }else if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
                    attemptRetryOnException("auth",
                            request, new AuthFailureError(""));
                }
            }
            if (responseContents != null) {
                networkResponse = new NetworkResponse(statusCode, responseContents,
                        responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
                    attemptRetryOnException("auth",
                            request, new AuthFailureError(networkResponse));
                } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
                        statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    attemptRetryOnException("redirect",
                            request, new AuthFailureError(networkResponse));
                } else {
                    // TODO: Only throw ServerError for 5xx status codes.
                    throw new ServerError(networkResponse);
                }
            } else {
                throw new NetworkError(e);
            }
        }
    }
}

Luego en el controlador de errores de volea use este código

@Override
        public void onErrorResponse(VolleyError error) {
             if (error instanceof AuthFailureError) {
                //handler error 401 unauthorized from here
            }
        }
    })

Feliz codificación: D

 2
Author: Afjalur Rahman Rana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-02 20:03:33

Así es como compruebo y error 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
Author: aung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-14 23:48:57

Manejo este problema manualmente:

  1. Descargar Biblioteca Volley de github y agregar en AndroidStudio proyecto

  2. Ir a com.android.volley.toolbox.HurlStack class

  3. Encontrar setConnectionParametersForRequest(connection, request); línea dentro de performRequest método

  4. Y finalmente añadir estos códigos belew de setConnectionParametersForRequest(connection, request); línea:

// for avoiding this exception : No authentication challenges found
        try {
            connection.getResponseCode();
        } catch (IOException e) {
            e.printStackTrace();
        }
 0
Author: Richi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-06 16:28:35