Gestion des erreurs jQuery Ajax, afficher les messages d'exception personnalisés


732

Existe-t-il un moyen d'afficher des messages d'exception personnalisés sous forme d'alerte dans mon message d'erreur jQuery AJAX?

Par exemple, si je veux lever une exception côté serveur via Struts by throw new ApplicationException("User name already exists");, je veux attraper ce message («le nom d'utilisateur existe déjà») dans le message d'erreur 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);
      }
    });
  }
});

Sur la deuxième alerte, où j'alerte l'erreur levée, je reçois undefinedet le code d'état est 500.

Je ne sais pas où je vais mal. Que puis-je faire pour résoudre ce problème?

Réponses:


359

Assurez-vous que vous définissez Response.StatusCodesur autre chose que 200. Écrivez le message de votre exception en utilisant Response.Write, puis utilisez ...

xhr.responseText

..dans votre javascript.


9
C'est toujours la bonne façon de le faire après 2 ans et demi ... :) Je suis allé un peu plus loin et retourne en fait mon propre objet JSON d'erreur qui peut gérer des erreurs simples ou multiples, assez bon pour la validation de formulaire côté serveur.
AlexCode

@Wilson C'était comme indiqué dans les autres réponses les mieux notées ici.
Sprintstar

3
Suis maintenant en 2014. JSON a dominé l'ère. Donc j'utilise xhr.responseJSON. : D
Ravi

5
xhr.responseJSON n'est défini que si vous vous assurez que le méta-type est défini (par exemple "Content-type: application / json"). C'est un problème que je viens de rencontrer; responseText a été défini - responseJSON ne l'a pas été.
Igor

218

Manette:

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

Voir le script:

$.ajax({
    type: "post", url: "/SomeController/SomeAction",
    success: function (data, text) {
        //...
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});

13
Ce n'est pas une réponse "correcte" à la question mais cela montre très certainement une solution de plus haut niveau au problème ... Nice!
Ryan Anderson

3
Je fais quelque chose de similaire. Cela fonctionne bien si tout est fait sur la boîte de développement. Si j'essaie de me connecter à partir d'une autre boîte sur le réseau, le xhr.responseText contient la page d'erreur générique html et non mon message personnalisé, voir stackoverflow.com/questions/3882752/…
jamiebarrow

6
Je pense que vous devriez également ajouter response.StatusCode = 500; ligne à la méthode OnException.
Alexander Prokofyev

4
J'ai adapté cela - car je voulais le code d'état 500, mais pour avoir le message d'exception dans la description de l'état (plutôt que "Erreur de serveur interne") - response.StatusCode = (int)HttpStatusCode.InternalServerError;etresponse.StatusDescription = filterContext.Exception.Message;
Kram

4
Si vous utilisez IIS7 ou supérieur, vous devrez peut-être ajouter: response.TrySkipIisCustomErrors = true;
James Gaunt

97

Du côté serveur:

     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

           }
 }

Côté client:

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

Gestion des erreurs Ajax générique

Si j'ai besoin de faire un traitement d'erreur générique pour toutes les demandes ajax. Je vais définir le gestionnaire ajaxError et afficher l'erreur sur un div nommé errorcontainer en haut du contenu 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);
                 });

82

Vous devez convertir le responseTextJSON. Utilisation de JQuery:

jsonValue = jQuery.parseJSON( jqXHR.responseText );
console.log(jsonValue.Message);

5
+1, car c'est actuellement la seule réponse correcte à cette question! Vous pouvez appeler "jsonValue.Message" pour obtenir le message d'exception.
Captain Sensible

2
En fait, ce n'est pas la bonne réponse, car la question ne concerne pas JSON et l'exemple de demande demande spécifiquement HTML comme réponse.
SingleShot

+1 Correct. Remarque, il est courant d'envoyer un objet encodé JSON via jqXHR.responseText (chaîne). Vous pouvez ensuite utiliser l'objet jsonValue comme vous le souhaitez. Utilisez la console Firebug pour examiner la réponse à l'aide de console.log (jsonValue).
jjwdesign

Cela me donne «Syncaxe UncaughtError: Numéro inattendu»
Ben Racicot

1
L'objet JSON analysé est rendu disponible via la propriété responseJSON de l'objet jqXHR. Il n'est donc pas nécessaire d'analyser la propriété responseText. Vous pouvez simplement faire: console.log (jqXHR.responseJSON.Message)
Eric D'Souza

37

Si vous appelez asp.net, cela renverra le titre du message d'erreur:

Je n'ai pas écrit moi-même tout formatErrorMessage mais je le trouve très utile.

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

22

C'est ce que j'ai fait et cela fonctionne jusqu'à présent dans une application MVC 5.

Le type de retour du contrôleur est 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"};
}

Et côté client, voici à quoi ressemble la fonction 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;
    }
});

20

Si quelqu'un est ici comme en 2016 pour la réponse, utilisez .fail()pour la gestion des erreurs car il .error()est obsolète à partir de jQuery 3.0

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

J'espère que ça aide


2
jqXHR.error()est obsolète (réellement supprimé) dans jQuery 3.0, mais les rappels erroret ne sont pas obsolètes, pour autant que je sache. success$.ajax()
Neil Conway du

16

Une solution générale / réutilisable

Cette réponse est fournie pour référence future à tous ceux qui se heurtent à ce problème. La solution se compose de deux choses:

  1. Exception personnalisée ModelStateException qui est levée lorsque la validation échoue sur le serveur (l'état du modèle signale des erreurs de validation lorsque nous utilisons des annotations de données et utilisons des paramètres d'action de contrôleur typés forts)
  2. Filtre d'erreur d'action du contrôleur personnalisé HandleModelStateExceptionAttribute qui intercepte une exception personnalisée et renvoie le statut d'erreur HTTP avec l'erreur d'état du modèle dans le corps

Cela fournit l'infrastructure optimale pour que les appels jQuery Ajax utilisent leur plein potentiel avec successet les errorgestionnaires.

Code côté client

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

Code côté serveur

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

    // create new user because validation was successful
}

L'ensemble du problème est détaillé dans cet article de blog où vous pouvez trouver tout le code pour l'exécuter dans votre application.


14

J'ai trouvé que c'était bien parce que je pouvais analyser le message que j'envoyais du serveur et afficher un message convivial à l'utilisateur sans le stacktrace ...

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

12

 error:function (xhr, ajaxOptions, thrownError) {
        alert(xhr.status);
        alert(thrownError);
      }
dans le code erreur ajax demande d'erreur de capture connectez-vous entre le client et le serveur si vous voulez afficher le message d'erreur de votre application

tel que

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

}


7

Cela est probablement dû au fait que les noms de champs JSON n'ont pas de guillemets.

Changez la structure JSON de:

{welcome:"Welcome"}

à:

{"welcome":"Welcome"}

1
Cela ne devrait pas avoir d'importance à moins que la clé ne soit un mot réservé dans JS. Je ne vois pas que ce soit le problème ici.
John Gibb

1
JSON.stringify ({welcome: "Welcome"}) -> {"welcome": "Welcome"}
Thulasiram

6

Vous avez un objet JSON de l'exception levée, dans l'objet xhr. Utilisez simplement

alert(xhr.responseJSON.Message);

L'objet JSON expose deux autres propriétés: 'ExceptionType' et 'StackTrace'


5

Je crois que le gestionnaire de réponse Ajax utilise le code d'état HTTP pour vérifier s'il y a eu une erreur.

Donc, si vous jetez simplement une exception Java sur votre code côté serveur mais que la réponse HTTP n'a pas de code d'état 500 jQuery (ou dans ce cas probablement l' objet XMLHttpRequest ) supposera simplement que tout allait bien.

Je dis cela parce que j'avais un problème similaire dans ASP.NET où je lançais quelque chose comme une ArgumentException ("Je ne sais pas quoi faire ...") mais le gestionnaire d'erreurs ne se déclenche pas.

J'ai ensuite réglé le Response.StatusCodesur 500 ou 200, que j'aie ou non une erreur.


5

jQuery.parseJSON est utile pour le succès et l'erreur.

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

5

Cette fonction génère essentiellement des clés API aléatoires uniques et dans le cas contraire, une boîte de dialogue contextuelle avec un message d'erreur apparaît.

Dans la page d'affichage:

<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>

Du contrôleur:

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

Le paramètre de rappel facultatif spécifie une fonction de rappel à exécuter lorsque la méthode load () est terminée. La fonction de rappel peut avoir différents paramètres:

Type: Fonction (jqXHR jqXHR, String textStatus, String errorThrown)

Une fonction à appeler si la demande échoue. La fonction reçoit trois arguments: l'objet jqXHR (dans jQuery 1.4.x, XMLHttpRequest), une chaîne décrivant le type d'erreur qui s'est produite et un objet d'exception facultatif, le cas échéant. Les valeurs possibles pour le deuxième argument (outre null) sont "timeout", "error", "abort" et "parsererror". Lorsqu'une erreur HTTP se produit, errorThrown reçoit la partie textuelle de l'état HTTP, telle que "Introuvable" ou "Erreur de serveur interne". Depuis jQuery 1.5, le paramètre d'erreur peut accepter un tableau de fonctions. Chaque fonction sera appelée tour à tour. Remarque: ce gestionnaire n'est pas appelé pour les requêtes de script inter-domaine et JSONP inter-domaine.


4
$("#save").click(function(){
    $("#save").ajaxError(function(event,xhr,settings,error){
        $(this).html{'error: ' (xhr ?xhr.status : '')+ ' ' + (error ? error:'unknown') + 'page: '+settings.url);
    });
});

3

Lancez une nouvelle exception sur le serveur en utilisant:

Response.StatusCode = 500

Response.StatusDescription = ex.Message ()

Je crois que le StatusDescription est retourné à l'appel Ajax ...

Exemple:

        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

2

Bien que cela fait de nombreuses années que cette question ne soit posée, je ne trouve toujours pas xhr.responseTextla réponse que je cherchais. Il m'a renvoyé une chaîne au format suivant:

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

que je ne veux absolument pas montrer aux utilisateurs. Ce que je cherchais est quelque chose comme ci-dessous:

alert(xhr.responseJSON.message);

xhr.responseJSON.message me donne le message exact de l'objet Json qui peut être montré aux utilisateurs.


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

S'il y a un formulaire est soumis avec valider

utilisez simplement le reste du code

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

... ... });


0

Nous devons d'abord définir <serviceDebug includeExceptionDetailInFaults = "True" /> dans web.config:

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

En plus de cela au niveau jquery dans la partie erreur, vous devez analyser la réponse d'erreur qui contient une exception comme:

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

Ensuite, en utilisant r.Message, vous pouvez réellement afficher le texte d'exception.

Vérifiez le code complet: http://www.codegateway.com/2012/04/jquery-ajax-handle-exception-thrown-by.html

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.