Android: ¿Cómo manejar el mensaje de error del servidor usando Volley?


Estoy usando Volley para mi aplicación Android para obtener datos de mi servidor. Funciona bien excepto al manejar el error desde mi servidor. Mi servidor envía esta respuesta cuando hay un error:

{
    "status": 400,
    "message": "Errors (2): A name is required- Julien is already used. Not creating."
}

Mi objetivo es obtener el mensaje y luego mostrarlo en un Toast. Seguí una muestra de cómo hacer esto, pero no funciona.

Ahí está mi oyente de errores:

public void onErrorResponse(VolleyError error) {
            int  statusCode = error.networkResponse.statusCode;
            NetworkResponse response = error.networkResponse;

            Log.d("testerror",""+statusCode+" "+response.data);
            // Handle your error types accordingly.For Timeout & No connection error, you can show 'retry' button.
            // For AuthFailure, you can re login with user credentials.
            // For ClientError, 400 & 401, Errors happening on client side when sending api request.
            // In this case you can check how client is forming the api and debug accordingly.
            // For ServerError 5xx, you can do retry or handle accordingly.
            if( error instanceof NetworkError) {
            } else if( error instanceof ClientError) {
            } else if( error instanceof ServerError) {
            } else if( error instanceof AuthFailureError) {
            } else if( error instanceof ParseError) {
            } else if( error instanceof NoConnectionError) {
            } else if( error instanceof TimeoutError) {
            }
            showProgress(false);
            mPasswordView.setError(getString(R.string.error_incorrect_password));
            mPasswordView.requestFocus();

        }

Y allí el resultado de mi depurador: testerror 4 400 [B@430b8d60

EDIT: Además mi error.getMessage() es null.

Así que no entiendo por qué mi respuesta variable.los datos no son la respuesta de mi servidor.

Si alguien sabe cómo puedo obtener el mensaje de mi servidor, será genial.

Thx,

Author: Submersed, 2014-02-19

2 answers

He implementado algo similar a esto, y es relativamente simple. Su mensaje de registro está imprimiendo lo que parece un galimatías, porque response.data es realmente un arreglo de bytes, no un String. Además, un VolleyError es realmente solo un Exceptionextendido, por lo que Excepción.Es probable que getMessage () no devuelva lo que está buscando a menos que anule los métodos de análisis para analizar su VolleyError en su clase extendida Request. Una forma muy básica de manejar esto sería hacer algo como:

//In your extended request class
@Override
protected VolleyError parseNetworkError(VolleyError volleyError){
        if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
                VolleyError error = new VolleyError(new String(volleyError.networkResponse.data));
                volleyError = error;
            }

        return volleyError;
    }
}

Si agrega esto a sus clases extendidas Request, su getMessage() al menos no debe devolver null. Normalmente no me molesto con esto, sin embargo, ya que es bastante fácil hacerlo todo desde dentro de su método onErrorResponse(VolleyError e).

Debería usar una biblioteca JSON para simplificar las cosas use Yo uso Gson por ejemplo o podría usar JSONObject s de Apache que no debería requerir una biblioteca externa adicional. El primer paso es obtener la respuesta JSON enviada desde su servidor como un String (de manera similar a lo que acabo de demostrar), a continuación, puede convertir opcionalmente a un JSONObject (usando ya sea JSONObjects y JsonArrays de apache, u otra biblioteca de su elección) o simplemente analizar el String usted mismo. Después de eso, solo tienes que mostrar el Toast.

Aquí hay un código de ejemplo para comenzar:

public void onErrorResponse(VolleyError error) {
     String json = null;

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

public String trimMessage(String json, String key){
    String trimmedString = null;

    try{
        JSONObject obj = new JSONObject(json);
        trimmedString = obj.getString(key);
    } catch(JSONException e){
        e.printStackTrace();
        return null;
    }

    return trimmedString;
}

//Somewhere that has access to a context
public void displayMessage(String toastString){
    Toast.makeText(context, toastString, Toast.LENGTH_LONG).show();
}
 149
Author: Submersed,
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-16 15:37:50

Pruebe esta clase para manejar todos los errores

public class VolleyErrorHelper {
        /**
         * Returns appropriate message which is to be displayed to the user
         * against the specified error object.
         *
         * @param error
         * @param context
         * @return
         */

        public static String getMessage (Object error , Context context){
            if(error instanceof TimeoutError){
                return context.getResources().getString(R.string.timeout);
            }else if (isServerProblem(error)){
                return handleServerError(error ,context);

            }else if(isNetworkProblem(error)){
                return context.getResources().getString(R.string.nointernet);
            }
            return context.getResources().getString(R.string.generic_error);

        }

        private static String handleServerError(Object error, Context context) {

            VolleyError er = (VolleyError)error;
            NetworkResponse response = er.networkResponse;
            if(response != null){
                switch (response.statusCode){

                    case 404:
                    case 422:
                    case 401:
                        try {
                            // server might return error like this { "error": "Some error occured" }
                            // Use "Gson" to parse the result
                            HashMap<String, String> result = new Gson().fromJson(new String(response.data),
                                    new TypeToken<Map<String, String>>() {
                                    }.getType());

                            if (result != null && result.containsKey("error")) {
                                return result.get("error");
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        // invalid request
                        return ((VolleyError) error).getMessage();

                    default:
                        return context.getResources().getString(R.string.timeout);
                }
            }

            return context.getResources().getString(R.string.generic_error);
        }

        private static boolean isServerProblem(Object error) {
            return (error instanceof ServerError || error instanceof AuthFailureError);
        }

        private static boolean isNetworkProblem (Object error){
            return (error instanceof NetworkError || error instanceof NoConnectionError);
        }
 6
Author: Mina Fawzy,
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
2015-11-13 12:13:52