tratamento de erros do jQuery Ajax, mostra mensagens de exceção personalizadas

728

Existe alguma maneira de mostrar mensagens de exceção personalizadas como um alerta na minha mensagem de erro do jQuery AJAX?

Por exemplo, se eu quiser lançar uma exceção no lado do servidor via Struts by throw new ApplicationException("User name already exists");, desejo capturar esta mensagem ('nome de usuário já existe') na mensagem de erro do 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);
      }
    });
  }
});

No segundo alerta, onde alerta o erro lançado, estou recebendo undefinede o código de status é 500.

Não sei ao certo onde estou errado. O que posso fazer para corrigir esse problema?

Roman C
fonte

Respostas:

357

Verifique se está definindo Response.StatusCodealgo diferente de 200. Escreva a mensagem de exceção usando Response.Writee use ...

xhr.responseText

..no seu javascript.

Sprintstar
fonte
9
Essa ainda é a maneira correta de fazer isso após 2 anos e meio ... :) Fui um pouco mais longe e, na verdade, retornei meu próprio objeto JSON de erro que pode lidar com erros únicos ou múltiplos, muito bom para a validação de formulários no lado do servidor.
AlexCode
@ Wilson Foi como mostrado nas outras respostas mais bem avaliadas aqui.
Sprintstar
3
Estou agora em 2014. JSON era dominada. Então eu uso xhr.responseJSON. : D
Ravi
5
xhr.responseJSON é definido apenas se você garantir que o meta-tipo esteja definido (por exemplo, "Tipo de conteúdo: application / json"). Esse é um problema que acabei de encontrar; responseText foi definido - responseJSON não foi.
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 script:

$.ajax({
    type: "post", url: "/SomeController/SomeAction",
    success: function (data, text) {
        //...
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});
AlexMAS
fonte
13
Esta não é uma resposta "correta" para a pergunta, mas certamente mostra uma solução de nível superior para o problema ... Legal!
Ryan Anderson
3
Estou fazendo algo parecido. Funciona bem se tudo for feito na caixa de desenvolvimento. Se eu tentar conectar-se de uma caixa diferente na rede, o xhr.responseText contém o html página de erro genérico e não a minha mensagem personalizada, consulte stackoverflow.com/questions/3882752/...
jamiebarrow
6
Eu acredito que você também deve adicionar response.StatusCode = 500; linha ao método OnException.
Alexander Prokofyev
4
Eu adaptei isso - desde que eu queria que o statuscode 500, mas para ter a mensagem de exceção na descrição do estado (em vez de "Erro de servidor interno") - response.StatusCode = (int)HttpStatusCode.InternalServerError;eresponse.StatusDescription = filterContext.Exception.Message;
Kram
4
Se você estiver usando o IIS7 ou superior, pode ser necessário adicionar: response.TrySkipIisCustomErrors = true;
James Gaunt
97

ServerSide:

     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

           }
 }

ClientSide:

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

Tratamento genérico de erros do Ajax

Se eu precisar fazer algum tratamento de erro genérico para todas as solicitações de ajax. Definirei o manipulador ajaxError e exibirei o erro em uma div chamada errorcontainer na parte superior do conteúdo 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
fonte
81

Você precisa converter o responseTextarquivo para JSON. Usando JQuery:

jsonValue = jQuery.parseJSON( jqXHR.responseText );
console.log(jsonValue.Message);
Sydney
fonte
5
+1 porque atualmente é a única resposta CORRETA a esta pergunta! Você pode chamar "jsonValue.Message" para obter a mensagem de exceção.
Captain Sensible
2
Na verdade, não é a resposta correta, porque a pergunta não pergunta sobre JSON e a solicitação de exemplo pede especificamente HTML como resposta.
SingleShot 19/07
+1 correto. Observe que é comum enviar um objeto codificado em JSON através do jqXHR.responseText (string). Em seguida, você pode usar o objeto jsonValue como precisar. Use o console do Firebug para revisar a resposta usando console.log (jsonValue).
Jjwdesign
Isto dá-me 'Uncaught SyntaxError: número inesperado'
Ben Racicot
1
O objeto JSON analisado é disponibilizado através da propriedade responseJSON do objeto jqXHR. Portanto, não há necessidade de analisar a propriedade responseText. Você pode apenas fazer: console.log (jqXHR.responseJSON.Message)
Eric D'Souza
37

Se você fizer uma chamada para o asp.net, isso retornará o título da mensagem de erro:

Eu não escrevi todo o formatErrorMessage, mas acho muito ú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
fonte
22

Foi o que fiz e funciona até agora em um aplicativo MVC 5.

O tipo de retorno do controlador é 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"};
}

E no lado do cliente é assim que a função ajax se parece

$.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
fonte
20

Se alguém estiver aqui, como em 2016, para obter a resposta, use o .fail()tratamento de erros como .error()descontinuado no jQuery 3.0

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

Espero que ajude

Aprendiz
fonte
2
jqXHR.error()foi descontinuado (realmente removido) no jQuery 3.0, mas os retornos de chamada errore não foram descontinuados, tanto quanto eu sei. success$.ajax()
Neil Conway
16

Uma solução geral / reutilizável

Esta resposta é fornecida para referência futura a todos aqueles que se deparam com esse problema. A solução consiste em duas coisas:

  1. Exceção customizada ModelStateException que é lançada quando a validação falha no servidor (o estado do modelo relata erros de validação quando usamos anotações de dados e usamos parâmetros de ação do controlador de tipo forte)
  2. Filtro de erro de ação do controlador customizado HandleModelStateExceptionAttribute que captura a exceção customizada e retorna o status de erro HTTP com o erro de estado do modelo no corpo

Isso fornece a infraestrutura ideal para que as chamadas do jQuery Ajax usem todo o seu potencial com successeerror manipuladores.

Código do lado do cliente

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

Código do lado do servidor

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

    // create new user because validation was successful
}

Todo o problema está detalhado nesta postagem do blog, onde você encontra todo o código para executar isso no seu aplicativo.

Robert Koritnik
fonte
14

Achei isso legal, porque eu podia analisar a mensagem que estava enviando do servidor e exibir uma mensagem amigável para o usuário sem o rastreamento de pilha ...

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

 error:function (xhr, ajaxOptions, thrownError) {
        alert(xhr.status);
        alert(thrownError);
      }
no erro de código solicitação ajax para erro de captura, conecte-se entre cliente e servidor, se desejar mostrar a mensagem de erro do seu aplicativo, envie no escopo com êxito

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

Provavelmente, isso é causado pelos nomes dos campos JSON sem aspas.

Altere a estrutura JSON de:

{welcome:"Welcome"}

para:

{"welcome":"Welcome"}
Cara
fonte
1
Isso não deve importar, a menos que a chave seja uma palavra reservada em JS. Não vejo esse problema aqui.
John Gibb
1
JSON.stringify ({welcome: "Welcome"}) -> {"welcome": "Welcome"}
Thulasiram
5

Acredito que o manipulador de resposta do Ajax use o código de status HTTP para verificar se houve um erro.

Portanto, se você apenas lançar uma exceção Java no código do lado do servidor, mas a resposta HTTP não tiver um código de status 500 jQuery (ou, nesse caso, provavelmente o XMLHttpRequest objeto ) assumirá que tudo estava bem.

Estou dizendo isso porque tive um problema semelhante no ASP.NET, onde estava lançando algo como uma ArgumentException ("Não sei o que fazer ..."), mas o manipulador de erros não estava disparando.

Em seguida, defino Response.StatusCode500 ou 200, independentemente de ter ou não um erro.

Vitor Silva
fonte
5

jQuery.parseJSON é útil para obter sucesso e erro.

$.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
fonte
5

Você tem um objeto JSON da exceção lançada, no objeto xhr. Apenas use

alert(xhr.responseJSON.Message);

O objeto JSON expõe duas outras propriedades: 'ExceptionType' e 'StackTrace'

Edika
fonte
5

Essa função basicamente gera chaves de API aleatórias exclusivas e, caso contrário, a caixa de diálogo pop-up com mensagem de erro será exibida.

Na Página de Visualização:

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

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

O parâmetro opcional de retorno de chamada especifica uma função de retorno de chamada a ser executada quando o método load () for concluído. A função de retorno de chamada pode ter parâmetros diferentes:

Tipo: Função (jqXHR jqXHR, String textStatus, String errorThrown)

Uma função a ser chamada se a solicitação falhar. A função recebe três argumentos: O objeto jqXHR (no jQuery 1.4.x, XMLHttpRequest), uma sequência que descreve o tipo de erro que ocorreu e um objeto de exceção opcional, se houver. Os valores possíveis para o segundo argumento (além de nulo) são "timeout", "error", "abort" e "parsererror". Quando ocorre um erro HTTP, errorThrown recebe a parte textual do status HTTP, como "Não encontrado" ou "Erro interno do servidor". A partir do jQuery 1.5, a configuração de erro pode aceitar uma matriz de funções. Cada função será chamada por sua vez. Nota: Este manipulador não é chamado para solicitações de script entre domínios e JSONP entre domínios.

Nɪsʜᴀɴᴛʜ ॐ
fonte
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
fonte
3

Lance uma nova exceção no servidor usando:

Response.StatusCode = 500

Response.StatusDescription = ex.Message ()

Acredito que o StatusDescription retorne à chamada do Ajax ...

Exemplo:

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

Embora já se passaram muitos anos desde que essa pergunta foi feita, ainda não encontro xhr.responseTexta resposta que estava procurando. Ele me retornou uma string no seguinte formato:

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

o que eu definitivamente não quero mostrar aos usuários. O que eu estava procurando é algo como abaixo:

alert(xhr.responseJSON.message);

xhr.responseJSON.message dá-me a mensagem exata do objeto Json que pode ser mostrada aos usuários.

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

Se houver algum formulário é enviado com validar

basta usar o restante do código

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

... ... });

Monzur
fonte
0

Primeiro, precisamos definir <serviceDebug includeExceptionDetailInFaults = "True" /> no web.config:

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

Além do que no nível do jquery na parte do erro, você precisa analisar a resposta de erro que contém uma exceção como:

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

Em seguida, usando r.Message, você pode realmente mostrar o texto da exceção.

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

Avinash
fonte