web-dev-qa-db-fra.com

Lors de l'exécution d'un message via ajax, une requête est renvoyée à la place du résultat JSON.

Javascript

jqXHR = $.ajax({ url: $frm.attr("action"), type: "POST", dataType: "json", cache: false,
  headers: headers, contentType: "application/json;charset=UTF-8", data: ko.mapping.toJSON(data, map),
  beforeSend: function(x) {
    if (x && x.overrideMimeType) {
      return x.overrideMimeType("application/json;charset=UTF-8");
    }
  }
});

jqXHR.fail(function(xhr, err, msg) {  /* xhr.responseText  NEED TO BE JSON!!! */ });

En chrome

En-têtes

Request Method:POST
Status Code:400 Bad Request
Request Headersview source
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4
Connection:keep-alive
Content-Length:10
Content-Type:application/json;charset=UTF-8
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.117 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payloadview source {Id:0}
Response Headersview source
Cache-Control:private
Content-Length:54
Content-Type:application/json; charset=utf-8
Date:Thu, 27 Feb 2014 14:01:59 GMT
Server:Microsoft-IIS/8.0
X-AspNet-Version:4.0.30319
X-AspNetMvc-Version:5.1
X-Powered-By:ASP.NET

Réponse

[{"Nom": "Nome", "ErrorMessage": "campo obrigatório."}]

Fonctionne en chrome!


Dans IE8

En-têtes (demande)

POST /Motivos/Salvar HTTP/1.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: pt-br
x-requested-with: XMLHttpRequest
Content-Type: application/json;charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
Content-Length: 10
Connection: Keep-Alive
Pragma: no-cache

En-têtes (Réponse)

HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.1
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 27 Feb 2014 13:51:46 GMT
Content-Length: 11

Bad Request

NE FONCTIONNE PAS !!

Asp.net MVC

Filtre

public class HandleExceptionAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            var ex = filterContext.Exception.GetBaseException();
            filterContext.Result = new JsonResult
            {
                JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                Data = new
                {
                    ex.Message,
                    ex.GetType().Name
                }
            };
            filterContext.ExceptionHandled = true;
        }
        else
        {
            base.OnException(filterContext);
        }
    }
}

Appliquer sur GlobalFilterCollection

Manette

[ValidateJsonAntiForgeryToken, HttpPost]
public virtual JsonResult Salvar(TViewModel viewModel)
{
    if (ModelState.IsValid)
    {
        TEntity model;
        if (default(TKey).Equals(viewModel.Id))
        {
            model = Mapper.Map<TEntity>(viewModel);
            AdicionarEntidade(model, viewModel);
        }
        else
        {
            model = Repositorio.Get(viewModel.Id);
            Mapper.Map(viewModel, model, typeof(TViewModel), typeof(TEntity));
            SalvarEntidade(model, viewModel);
        }

        return SalvarResult(model);
    }

    Response.StatusCode = 400;
    return Json(ModelState.ToJson(), JsonRequestBehavior.AllowGet);
}

Extenssion

public static object ToJson(this ModelStateDictionary dic, params string[] othersMessages)
{
    var states = (from e in dic where e.Value.Errors.Count > 0
                  select new { Name = e.Key, e.Value.Errors[0].ErrorMessage }).ToList();

    if (othersMessages != null)
        foreach (var message in othersMessages)
            states.Add(new { Name = "", ErrorMessage = message });

    return states;
}

Des questions

  • Pourquoi ne pas avoir l'objet xhr.resposeText? 
  • Comment récupérer JSON de la même manière que je récupère dans Chrome? 

J'ai besoin du JSON pour remplir le formulaire!

Notes: 03/11/2014

Quand j'ajoute Response.TrySkipIisCustomErrors = true; dans mon contrôleur, ça marche! responseText renvoie le json. Pourquoi?

22
ridermansb

Pensez qu’il s’agit d’un problème lié à IIS qui tente d’utiliser une réponse d’erreur personnalisée au lieu d’envoyer le message d’erreur généré par le contrôleur.

<system.webServer>
    ...
    <httpErrors existingResponse="PassThrough"></httpErrors>
    ...
</system.webServer>

Ou

Response.TrySkipIisCustomErrors = true;

Référence - https://stackoverflow.com/a/4029197/1304559

Découvrez ce blog http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors

Le code de réponse étant défini sur 400, IIS remplace votre contenu par son contenu de page d'erreur personnalisé.

31
aravind

Votre réponse revient avec l'en-tête http Content-Type: text/html, mais elle devrait être application/json. Ce n'est pas un problème dans Chrome (et vous n'obtenez pas des avertissements d'incompatibilité dans la console) car vous vous appuyez sur overrideMimeType ... qui, vous l'avez deviné, n'est pas compatible avec IE. En fait, ce qui suit n’est jamais exécuté sur les anciennes versions d’IE:

if (x && x.overrideMimeType) {
  return x.overrideMimeType("application/json;charset=UTF-8");
}

Votre solution pourrait être de vous assurer que le contenu est servi avec le type de contenu correct. Si vous connaissez les outils de modification tels que Burp Suite , vous pouvez ajouter le bon en-tête à la volée et voir si cela résout le problème. J'éviterais probablement d'inclure des méthodes telles que AddHeader et de voir s'il est possible de résoudre ce problème à un niveau de routage supérieur, peut-être.

2
o.v.

Le problème que je vois est que vous essayez de définir le codage du JSON sur UTF-8. Normalement, cela fonctionne très bien, cependant, sur IIS, une erreur personnalisée permet de signaler que le format UTF-8 n’est pas nécessaire. 

Peu d'autres choses à noter. Vous effectuez un POST, le serveur attend donc un fichier json. Si aucun n'est fourni, il ne saura pas quoi faire.

2
jemiloii

J'ai rempli un test d'échec qui devrait aider.

$.post($frm.attr("action"), ko.mapping.toJSON(data, map))
.done(function (dataVal) {
    //process dataVal
    var mystruct = GenerateCache($.parseJSON(dataVal));
})
.fail(function (jqxhr, textStatus, error) {
    if (jqxhr.responseText.indexOf("YourMoniker") != -1) {
        parseData($.parseJSON(jqxhr.responseText));
    } else {
        var err = textStatus + ', ' + error;
        console.log("Request Failed: " + err);
    }
});


function GenerateCache(data) {
    var obj = function () { };
    obj.prototype = data;
    return new obj();
}

Examinez plus particulièrement le traitement des erreurs dans la section .fail.

1
CaptainBli

IE (toutes les versions, y compris IE11) mettra "Bad Request" dans le texte du statut et ignorera le JSON que vous avez entré comme message.

Afin d'utiliser le xhr.responseText dans IE en cas d'erreur, vous devez générer une exception au lieu de renvoyer un Json ou un JsonResult avec HttpStatusCode.BadRequest;

Alors ... avant:

Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = "There is already a distribution set which covers part or all of this period" });

Cela fonctionne dans Chrome, FF et tous les navigateurs sensés, vraiment. Après:

throw new Exception("You have posted invalid datas.");

En tant qu'exception non gérée, elle sera transmise au navigateur sous forme de réponse. Elle fonctionnera sous Chrome, FF et même dans IE. Ce n'est pas gracieux, comme toutes les exceptions non gérées (ou juste des exceptions, d'ailleurs), mais il vous permettra de recevoir une réponse appropriée.

0
Nomenator

Ce n'est pas votre contrôleur, ça fonctionne bien. Un champ obligatoire est manquant: IE et Chrome renvoient le code d'état 400 Bad Request - mais seul Chrome traite correctement la responseText et vous donne [{"Name":"Nome","ErrorMessage":"campo obrigatório."}], ce qui signifie que vous avez un champ de formulaire manquant.

Bien que j'aie cherché partout et que je n'ai trouvé aucune référence à des bogues IE spécifiques lors du traitement de XMLHttpRequest.responseText avec des codes de statut non-200, il semble que IE remplace le corps de votre réponse par sa propre:

Headers (Response)

HTTP/1.1 400 Bad Request
...
Content-Length: 11

Bad Request

Indique que le "contenu", tel qu'il est traité, correspond au texte d'état "Requête incorrecte" et non à la réponse JSON appropriée (que Chrome lit sous la forme suivante: longueur du contenu 54, par exemple). Cela pourrait signifier que IE est en train de jeter votre corps de réponse (j'en doute, ce serait foutrement incroyable) ou qu'il ne soit simplement pas traité "correctement". Essayez de vider le reste de votre objet jqXHR et les arguments de votre gestionnaire fail pour voir si vous pouvez le trouver quelque part.

0
Brian North