Manejo de errores de jQuery Ajax, muestra mensajes de excepción personalizados

729

¿Hay alguna forma de mostrar mensajes de excepción personalizados como alerta en mi mensaje de error jQuery AJAX?

Por ejemplo, si quiero lanzar una excepción en el lado servidor a través de puntales por throw new ApplicationException("User name already exists");, quiero coger este mensaje (nombre de usuario ya existe ') en el mensaje de error jQuery AJAX.

jQuery("#save").click(function () {
  if (jQuery('#form').jVal()) {
    jQuery.ajax({
      type: "POST",
      url: "saveuser.do",
      dataType: "html",
      data: "userId=" + encodeURIComponent(trim(document.forms[0].userId.value)),
      success: function (response) {
        jQuery("#usergrid").trigger("reloadGrid");
        clear();
        alert("Details saved successfully!!!");
      },
      error: function (xhr, ajaxOptions, thrownError) {
        alert(xhr.status);
        alert(thrownError);
      }
    });
  }
});

En la segunda alerta, donde alerta el error arrojado, recibo undefinedy el código de estado es 500.

No estoy seguro de a dónde me estoy equivocando. ¿Qué puedo hacer para solucionar este problema?

Romana C
fuente

Respuestas:

358

Asegúrate de estar configurando Response.StatusCodealgo diferente a 200. Escribe el mensaje de tu excepción usando Response.Write, luego usa ...

xhr.responseText

..en su javascript.

Sprintstar
fuente
99
Esta sigue siendo la forma correcta de hacerlo después de 2 años y medio ... :) Fui un poco más lejos y en realidad devolví mi propio objeto JSON de error que puede manejar errores únicos o múltiples, bastante bueno para la validación de formularios del lado del servidor.
AlexCode
@Wilson Fue como se muestra en las otras respuestas de alta calificación aquí.
Sprintstar
3
Ahora estoy en 2014. JSON dominó la era. Entonces lo uso xhr.responseJSON. : D
Ravi
55
xhr.responseJSON solo se establece si se asegura de que el metatipo esté configurado (por ejemplo, "Content-type: application / json"). Ese es un problema que acabo de encontrar; responseText se configuró; responseJSON no.
Igor
217

Controlador:

public class ClientErrorHandler : FilterAttribute, IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        var response = filterContext.RequestContext.HttpContext.Response;
        response.Write(filterContext.Exception.Message);
        response.ContentType = MediaTypeNames.Text.Plain;
        filterContext.ExceptionHandled = true;
    }
}

[ClientErrorHandler]
public class SomeController : Controller
{
    [HttpPost]
    public ActionResult SomeAction()
    {
        throw new Exception("Error message");
    }
}

Ver guión:

$.ajax({
    type: "post", url: "/SomeController/SomeAction",
    success: function (data, text) {
        //...
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});
AlexMAS
fuente
13
Esta no es una respuesta "correcta" a la pregunta, pero sin duda muestra una solución de mayor nivel al problema ... ¡Genial!
Ryan Anderson
3
Estoy haciendo algo similar Funciona bien si todo se hace en el cuadro de desarrollo. Si intento conectarme desde un cuadro diferente en la red, el xhr.responseText contiene la página de error genérico html y no mi mensaje personalizado, consulte stackoverflow.com/questions/3882752/…
jamiebarrow
66
Creo que también deberías agregar response.StatusCode = 500; línea al método OnException.
Alexander Prokofyev
44
He adaptado este - ya que yo quería que el statuscode 500, pero para tener el mensaje de excepción en la descripción de estado (en lugar de "error interno del servidor") - response.StatusCode = (int)HttpStatusCode.InternalServerError;yresponse.StatusDescription = filterContext.Exception.Message;
Kram
44
Si está utilizando IIS7 o superior, es posible que deba agregar: respuesta. TrySkipIisCustomErrors = true;
James Gaunt
97

Lado del servidor:

     doPost(HttpServletRequest request, HttpServletResponse response){ 
            try{ //logic
            }catch(ApplicationException exception){ 
               response.setStatus(400);
               response.getWriter().write(exception.getMessage());
               //just added semicolon to end of line

           }
 }

Lado del cliente:

 jQuery.ajax({// just showing error property
           error: function(jqXHR,error, errorThrown) {  
               if(jqXHR.status&&jqXHR.status==400){
                    alert(jqXHR.responseText); 
               }else{
                   alert("Something went wrong");
               }
          }
    }); 

Manejo genérico de errores Ajax

Si necesito hacer un manejo genérico de errores para todas las solicitudes ajax. Estableceré el controlador ajaxError y mostraré el error en un div llamado errorcontainer en la parte superior del contenido html.

$("div#errorcontainer")
    .ajaxError(
        function(e, x, settings, exception) {
            var message;
            var statusErrorMap = {
                '400' : "Server understood the request, but request content was invalid.",
                '401' : "Unauthorized access.",
                '403' : "Forbidden resource can't be accessed.",
                '500' : "Internal server error.",
                '503' : "Service unavailable."
            };
            if (x.status) {
                message =statusErrorMap[x.status];
                                if(!message){
                                      message="Unknown Error \n.";
                                  }
            }else if(exception=='parsererror'){
                message="Error.\nParsing JSON Request failed.";
            }else if(exception=='timeout'){
                message="Request Time out.";
            }else if(exception=='abort'){
                message="Request was aborted by the server";
            }else {
                message="Unknown Error \n.";
            }
            $(this).css("display","inline");
            $(this).html(message);
                 });
Sanjeev Kumar Dangi
fuente
81

Necesita convertir el responseTexta JSON. Usando JQuery:

jsonValue = jQuery.parseJSON( jqXHR.responseText );
console.log(jsonValue.Message);
Sydney
fuente
55
¡+1 porque esta es actualmente la única respuesta CORRECTA a esta pregunta! Puede llamar a "jsonValue.Message" para obtener el mensaje de excepción.
Capitán Sensible
2
En realidad, no es la respuesta correcta porque la pregunta no pregunta sobre JSON y la solicitud de ejemplo solicita específicamente HTML como respuesta.
SingleShot
+1 correcto. Tenga en cuenta que es común enviar un objeto codificado JSON a través de jqXHR.responseText (cadena). Luego, puede usar el objeto jsonValue como lo necesite. Use la consola Firebug para revisar la respuesta usando console.log (jsonValue).
jjwdesign
Esto me da 'Untaught SyntaxError: número inesperado'
Ben Racicot
1
El objeto JSON analizado está disponible a través de la propiedad responseJSON del objeto jqXHR. Por lo tanto, no es necesario analizar la propiedad responseText. Simplemente puede hacer: console.log (jqXHR.responseJSON.Message)
Eric D'Souza el
37

Si realiza una llamada a asp.net, esto devolverá el título del mensaje de error:

No escribí todo el mensaje FormatErrorMessage, pero lo encuentro muy útil.

function formatErrorMessage(jqXHR, exception) {

    if (jqXHR.status === 0) {
        return ('Not connected.\nPlease verify your network connection.');
    } else if (jqXHR.status == 404) {
        return ('The requested page not found. [404]');
    } else if (jqXHR.status == 500) {
        return ('Internal Server Error [500].');
    } else if (exception === 'parsererror') {
        return ('Requested JSON parse failed.');
    } else if (exception === 'timeout') {
        return ('Time out error.');
    } else if (exception === 'abort') {
        return ('Ajax request aborted.');
    } else {
        return ('Uncaught Error.\n' + jqXHR.responseText);
    }
}


var jqxhr = $.post(addresshere, function() {
  alert("success");
})
.done(function() { alert("second success"); })
.fail(function(xhr, err) { 

    var responseTitle= $(xhr.responseText).filter('title').get(0);
    alert($(responseTitle).text() + "\n" + formatErrorMessage(xhr, err) ); 
})
Sam Jones
fuente
22

Esto es lo que hice y funciona hasta ahora en una aplicación MVC 5.

El tipo de retorno del controlador es ContentResult.

public ContentResult DoSomething()
{
    if(somethingIsTrue)
    {
        Response.StatusCode = 500 //Anything other than 2XX HTTP status codes should work
        Response.Write("My Message");
        return new ContentResult();
    }

    //Do something in here//
    string json = "whatever json goes here";

    return new ContentResult{Content = json, ContentType = "application/json"};
}

Y en el lado del cliente, así es como se ve la función ajax

$.ajax({
    type: "POST",
    url: URL,
    data: DATA,
    dataType: "json",
    success: function (json) {
        //Do something with the returned json object.
    },
    error: function (xhr, status, errorThrown) {
        //Here the status code can be retrieved like;
        xhr.status;

        //The message added to Response object in Controller can be retrieved as following.
        xhr.responseText;
    }
});
Cengiz Araz
fuente
20

Si alguien está aquí como en 2016 para obtener la respuesta, úsela .fail()para el manejo de errores, ya que .error()está obsoleto a partir de jQuery 3.0

$.ajax( "example.php" )
  .done(function() {
    alert( "success" );
  })
  .fail(function(jqXHR, textStatus, errorThrown) {
    //handle error here
  })

Espero que ayude

Aprendiz
fuente
2
jqXHR.error()está en desuso (en realidad eliminado) en jQuery 3.0, pero las devoluciones de llamada errory no están en desuso, por lo que yo sé. success$.ajax()
Neil Conway
16

Una solución general / reutilizable

Esta respuesta se proporciona para referencia futura a todos aquellos que se topan con este problema. La solución consta de dos cosas:

  1. Excepción personalizada ModelStateException que se produce cuando la validación falla en el servidor (el estado del modelo informa errores de validación cuando usamos anotaciones de datos y utilizamos parámetros de acción de controlador con tipo fuerte)
  2. Filtro de error de acción del controlador personalizado HandleModelStateExceptionAttribute que detecta una excepción personalizada y devuelve el estado de error HTTP con un error de estado del modelo en el cuerpo

Esto proporciona la infraestructura óptima para que las llamadas jQuery Ajax utilicen todo su potencial con successy errormanejadores.

Código del lado del cliente

$.ajax({
    type: "POST",
    url: "some/url",
    success: function(data, status, xhr) {
        // handle success
    },
    error: function(xhr, status, error) {
        // handle error
    }
});

Código del lado del servidor

[HandleModelStateException]
public ActionResult Create(User user)
{
    if (!this.ModelState.IsValid)
    {
        throw new ModelStateException(this.ModelState);
    }

    // create new user because validation was successful
}

Todo el problema se detalla en esta publicación de blog donde puede encontrar todo el código para ejecutar esto en su aplicación.

Robert Koritnik
fuente
14

Encontré que esto era bueno porque podía analizar el mensaje que estaba enviando desde el servidor y mostrar un mensaje amigable al usuario sin el seguimiento de la pila ...

error: function (response) {
      var r = jQuery.parseJSON(response.responseText);
      alert("Message: " + r.Message);
      alert("StackTrace: " + r.StackTrace);
      alert("ExceptionType: " + r.ExceptionType);
}
diamante loco
fuente
11

 error:function (xhr, ajaxOptions, thrownError) {
        alert(xhr.status);
        alert(thrownError);
      }
en la solicitud de error de código ajax para error de captura, conéctese entre el cliente y el servidor si desea mostrar el mensaje de error de su aplicación enviado en el alcance exitoso

como

success: function(data){
   //   data is object  send  form server 
   //   property of data 
   //   status  type boolean 
   //   msg     type string
   //   result  type string
  if(data.status){ // true  not error 
         $('#api_text').val(data.result);
  }
  else 
  {
      $('#error_text').val(data.msg);
  }

}

Wara Haii
fuente
7

Esto probablemente se deba a que los nombres de campo JSON no tienen comillas.

Cambie la estructura JSON de:

{welcome:"Welcome"}

a:

{"welcome":"Welcome"}
Chico
fuente
1
Esto no debería importar a menos que la clave sea una palabra reservada en JS. No veo que este sea el problema aquí.
John Gibb
1
JSON.stringify ({bienvenido: "Bienvenido"}) -> {"bienvenido": "Bienvenido"}
Thulasiram
5

Creo que el controlador de respuesta de Ajax usa el código de estado HTTP para verificar si hubo un error.

Entonces, si solo arroja una excepción de Java en el código del lado del servidor, pero la respuesta HTTP no tiene un código de estado 500 jQuery (o en este caso probablemente XMLHttpRequest) objeto ) simplemente asumirá que todo estaba bien.

Lo digo porque tuve un problema similar en ASP.NET donde estaba lanzando algo como una excepción ArgumentException ("No sé qué hacer ...") pero el controlador de errores no se estaba disparando.

Luego configuré Response.StatusCode500 o 200 si tuve un error o no.

Vitor Silva
fuente
5

jQuery.parseJSON es útil para el éxito y el error.

$.ajax({
    url: "controller/action",
    type: 'POST',
    success: function (data, textStatus, jqXHR) {
        var obj = jQuery.parseJSON(jqXHR.responseText);
        notify(data.toString());
        notify(textStatus.toString());
    },
    error: function (data, textStatus, jqXHR) { notify(textStatus); }
});
Nuri YILMAZ
fuente
5

Tiene un objeto JSON de la excepción lanzada, en el objeto xhr. Solo usa

alert(xhr.responseJSON.Message);

El objeto JSON expone otras dos propiedades: 'ExceptionType' y 'StackTrace'

Edika
fuente
5

Esta función básicamente genera claves API aleatorias únicas y, en caso de que no lo haga, aparecerá un cuadro de diálogo emergente con un mensaje de error

En la página de visualización:

<div class="form-group required">
    <label class="col-sm-2 control-label" for="input-storename"><?php echo $entry_storename; ?></label>
    <div class="col-sm-6">
        <input type="text" class="apivalue"  id="api_text" readonly name="API" value="<?php echo strtoupper(substr(md5(rand().microtime()), 0, 12)); ?>" class="form-control" />                                                                    
        <button type="button" class="changeKey1" value="Refresh">Re-Generate</button>
    </div>
</div>

<script>
$(document).ready(function(){
    $('.changeKey1').click(function(){
          debugger;
        $.ajax({
                url  :"index.php?route=account/apiaccess/regenerate",
                type :'POST',
                dataType: "json",
                async:false,
                contentType: "application/json; charset=utf-8",
                success: function(data){
                  var result =  data.sync_id.toUpperCase();
                        if(result){
                          $('#api_text').val(result);
                        }
                  debugger;
                  },
                error: function(xhr, ajaxOptions, thrownError) {
                  alert(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText);
                }

        });
    });
  });
</script>

Del controlador:

public function regenerate(){
    $json = array();
    $api_key = substr(md5(rand(0,100).microtime()), 0, 12);
    $json['sync_id'] = $api_key; 
    $json['message'] = 'Successfully API Generated';
    $this->response->addHeader('Content-Type: application/json');
    $this->response->setOutput(json_encode($json));
}

El parámetro opcional de devolución de llamada especifica una función de devolución de llamada que se ejecutará cuando se complete el método load (). La función de devolución de llamada puede tener diferentes parámetros:

Tipo: Función (jqXHR jqXHR, String textStatus, String errorThrown)

Una función que se llamará si la solicitud falla. La función recibe tres argumentos: el objeto jqXHR (en jQuery 1.4.x, XMLHttpRequest), una cadena que describe el tipo de error que se produjo y un objeto de excepción opcional, si se produjo uno. Los valores posibles para el segundo argumento (además de nulo) son "timeout", "error", "abort" y "parsererror". Cuando se produce un error HTTP, errorThrown recibe la parte textual del estado HTTP, como "No encontrado" o "Error interno del servidor". A partir de jQuery 1.5, la configuración de error puede aceptar una variedad de funciones. Cada función se llamará por turno. Nota: No se llama a este controlador para las solicitudes JSONP entre dominios y secuencias de comandos entre dominios.

Nɪsʜᴀɴᴛʜ ॐ
fuente
4
$("#save").click(function(){
    $("#save").ajaxError(function(event,xhr,settings,error){
        $(this).html{'error: ' (xhr ?xhr.status : '')+ ' ' + (error ? error:'unknown') + 'page: '+settings.url);
    });
});
ibrahim ozboluk
fuente
3

Lanza una nueva excepción en el servidor usando:

Response.StatusCode = 500

Response.StatusDescription = ex.Message ()

Creo que StatusDescription se devuelve a la llamada Ajax ...

Ejemplo:

        Try

            Dim file As String = Request.QueryString("file")

            If String.IsNullOrEmpty(file) Then Throw New Exception("File does not exist")

            Dim sTmpFolder As String = "Temp\" & Session.SessionID.ToString()

            sTmpFolder = IO.Path.Combine(Request.PhysicalApplicationPath(), sTmpFolder)

            file = IO.Path.Combine(sTmpFolder, file)

            If IO.File.Exists(file) Then

                IO.File.Delete(file)

            End If

        Catch ex As Exception

            Response.StatusCode = 500

            Response.StatusDescription = ex.Message()

        End Try
Steffan
fuente
2

Aunque han pasado muchos años desde que se hizo esta pregunta, todavía no encuentro xhr.responseTextla respuesta que estaba buscando. Me devolvió una cadena en el siguiente formato:

"{"error":true,"message":"The user name or password is incorrect"}"

que definitivamente no quiero mostrar a los usuarios. Lo que estaba buscando es algo como a continuación:

alert(xhr.responseJSON.message);

xhr.responseJSON.message me da el mensaje exacto del objeto Json que se puede mostrar a los usuarios.

Saket
fuente
1
$("#fmlogin").submit(function(){
   $("#fmlogin").ajaxError(function(event,xhr,settings,error){
       $("#loading").fadeOut('fast');       
       $("#showdata").fadeIn('slow');   
       $("#showdata").html('Error please, try again later or reload the Page. Reason: ' + xhr.status);
       setTimeout(function() {$("#showdata").fadeOut({"opacity":"0"})} , 5500 + 1000); // delays 1 sec after the previous one
    });
});

Si hay algún formulario se envía con validar

simplemente usa el resto del código

$("#fmlogin").validate({...

... ... });

Monzur
fuente
0

Primero necesitamos establecer <serviceDebug includeExceptionDetailInFaults = "True" /> en web.config:

<serviceBehaviors> 
 <behavior name=""> 
  <serviceMetadata httpGetEnabled="true" /> 
    **<serviceDebug includeExceptionDetailInFaults="true" />** 
 </behavior> 
</serviceBehaviors>

Además de eso en el nivel de jquery en la parte de error, debe analizar la respuesta de error que contiene una excepción como:

.error(function (response, q, t) { 
  var r = jQuery.parseJSON(response.responseText); 
}); 

Luego, utilizando r.Message, puede mostrar realmente texto de excepción.

Verifique el código completo: http://www.codegateway.com/2012/04/jquery-ajax-handle-exception-thrown-by.html

Avinash
fuente