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-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!
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 !!
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
[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);
}
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;
}
J'ai besoin du JSON pour remplir le formulaire!
Quand j'ajoute Response.TrySkipIisCustomErrors = true;
dans mon contrôleur, ça marche! responseText renvoie le json. Pourquoi?
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é.
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.
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.
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
.
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.
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.