Ao executar post via ajax, Pedido incorreto é retornado em vez do JSON resultado
-
23-12-2019 - |
Pergunta
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!!! */ });
No Google Chrome
Cabeçalhos
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
Resposta
[{"Nome":"Nome","ErrorMessage":"campo obrigatório."}]
Funciona no chrome!
No IE8
Os Cabeçalhos (Pedido)
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
Os Cabeçalhos (Resposta)
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
NÃO FUNCIONA!!
Asp.net MVC
Filtro
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);
}
}
}
Aplicar no GlobalFilterCollection
Controlador de
[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;
}
Perguntas
- Por que não ter o xhr.resposeText objeto?
- Como recuperar JSON, da mesma forma que eu recuperar no Chrome?
Eu preciso de JSON para preencher o formulário!
Notas:03/11/2014
Quando eu adicionar Response.TrySkipIisCustomErrors = true;
na minha controler, ele funciona!responseText retorna json.Por quê?
Solução
Acho que este é um problema com o IIS tentando usar resposta de erro personalizada em vez de enviar a mensagem de erro que o controlador está a gerar.
<system.webServer>
...
<httpErrors existingResponse="PassThrough"></httpErrors>
...
</system.webServer>
Ou
Response.TrySkipIisCustomErrors = true;
De referência - https://stackoverflow.com/a/4029197/1304559
Confira este post de blog http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors
Desde o código de resposta é definida como 400, o IIS substitui o seu conteúdo com a sua página de erro personalizada de conteúdo
Outras dicas
O problema que eu estou vendo é que sua tentativa de definir a codificação do JSON para UTF-8.Normalmente ele funciona muito bem, no entanto, no IIS, tem um erro personalizado para relatar que o UTF-8 não é necessário.
Algumas outras coisas para observação.Você está fazendo uma PÓS, de modo que o servidor vai estar esperando um arquivo json.Se for fornecido nenhum, ele não vai saber o que fazer.
Sua resposta vem de trás com Content-Type: text/html
cabeçalho http, mas ele deve ser application/json
.Este não é um problema no Chrome (e você não vem incompatibilidade de avisos no console) porque você está confiando em overrideMimeType
...o que, você adivinhou-lo, não é o IE-friendly.Na verdade, o seguinte nunca é executado em versões mais antigas do IE:
if (x && x.overrideMimeType) {
return x.overrideMimeType("application/json;charset=UTF-8");
}
Sua solução poderia ser a de se certificar de que o conteúdo é servido com o tipo de conteúdo correto.Se você estiver familiarizado com a adulteração de ferramentas como Burp Suite, você poderia adicionar o cabeçalho correto on-the-fly e ver se isso corrige o problema.Eu provavelmente iria evitar inlining métodos como AddHeader
e ver se há uma maneira isto pode ser fixado em um maior encaminhamento, talvez de nível.
Eu tenho enchido em uma falha de teste que deve ajudar.
$.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();
}
Procurar especificamente no tratamento de erros no .fail
a seção.
Não é o controlador, que está funcionando bem.Está faltando um campo necessário:tanto o IE e o Chrome são de retornar o código de status 400 Bad Request
- mas apenas o Chrome é processar corretamente o responseText
e dando-lhe [{"Name":"Nome","ErrorMessage":"campo obrigatório."}]
ou seja, você tem uma falta de campo de formulário.
Embora eu tenha procurado em todo e não encontrei nenhuma referência específica IE erros no processamento de XMLHttpRequest.responseText
com os não-200 códigos de status, parece que o IE é substituir o seu corpo de resposta com o seu próprio:
Headers (Response)
HTTP/1.1 400 Bad Request
...
Content-Length: 11
Bad Request
Indica que o "conteúdo" como ele trata é o "Bad Request" status de texto, não é a adequada resposta json (que o google Chrome, lê-se o conteúdo de comprimento 54, por exemplo).Isto pode significar ou seja, é de descartar o corpo da resposta (que eu duvido que ele, que seria sangrenta incrível), ou não é só ser processado "adequadamente". Tente despejar o resto do seu jqXHR
objeto e os argumentos para a sua fail
processador para ver se você pode encontrá-lo em algum lugar.
Internet explorer (todas as versões, incluindo o IE11) vai colocar "Bad Request" no texto de status e ignorar o JSON você colocar em como a mensagem.
Para usar o xhr.responseText-no-IE no de erro, você precisa jogar uma exceção em vez de retornar um Json ou JsonResult com HttpStatusCode.BadRequest;
Então...antes:
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = "There is already a distribution set which covers part or all of this period" });
Isso funciona no Chrome, FF e qualquer sã navegador, realmente.Depois:
throw new Exception("You have posted invalid datas.");
Como uma exceção não tratada, ela será transmitida para o browser como uma resposta, isso vai funcionar no Chrome, FF e até no IE.Isso não é normal, mesmo que todas as exceções não tratadas (ou apenas exceções, para que o assunto), mas ele vai fazer o trabalho de deixar você receber uma resposta apropriada.