jquery - por - Al realizar una publicación a través de ajax, se devuelve una Solicitud incorrecta en lugar del resultado JSON
recibir datos por ajax jquery (6)
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 cromo
Encabezados
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
Respuesta
[{"Nombre": "Nome", "ErrorMessage": "campo obrigatório."}]
Funciona en cromo!
En IE8
Encabezados (Solicitud)
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
Encabezados (Respuesta)
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
¡¡NO TRABAJO!!
Asp.net MVC
Filtrar
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 en GlobalFilterCollection
Controlador
[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);
}
Extensión
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;
}
Preguntas
- ¿Por qué no tener el objeto xhr.resposeText?
- ¿Cómo recuperar JSON de la misma manera que me recupero en Chrome?
¡Necesito el JSON para rellenar el formulario!
Notas: 03/11/2014
Cuando agrego Response.TrySkipIisCustomErrors = true;
en mi control, funciona! responseText devuelve el json. ¿Por qué?
El problema que estoy viendo es que estás intentando configurar la codificación de JSON en UTF-8. Normalmente funciona bien, sin embargo, en IIS, tiene un error personalizado para informar que el UTF-8 no es necesario.
Algunas otras cosas a tener en cuenta. Estás haciendo un POST, por lo que el servidor esperará un archivo json. Si no se proporciona ninguno, no sabrá qué hacer.
He completado una prueba de falla que debería ayudar.
$.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();
}
Mire específicamente el manejo de errores en la sección .fail
.
IE (todas las versiones, incluido IE11) colocará "Solicitud incorrecta" en el texto de estado e ignorará el JSON que ingresó como mensaje.
Para utilizar el xhr.responseText en IE en caso de error, debe lanzar una excepción en lugar de devolver un Json o JsonResult con HttpStatusCode.BadRequest;
Entonces ... antes
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { Message = "There is already a distribution set which covers part or all of this period" });
Esto funciona en Chrome, FF y cualquier navegador sano, realmente. Después:
throw new Exception("You have posted invalid datas.");
Como una excepción no controlada, se pasará al navegador como respuesta, esto funcionará en Chrome, FF e incluso en IE. No es elegante, al igual que todas las excepciones no manejadas (o solo excepciones, para el caso), pero hará el trabajo de permitirle recibir una respuesta adecuada.
No es tu controlador, está funcionando bien. Le falta un campo obligatorio: tanto IE como Chrome están devolviendo el código de estado 400 Bad Request
, pero solo Chrome está procesando adecuadamente el texto de responseText
y le proporciona [{"Name":"Nome","ErrorMessage":"campo obrigatório."}]
lo que significa que tiene un campo de formulario faltante.
Aunque he buscado por todas partes y no he encontrado ninguna referencia a errores de IE específicos en el procesamiento de XMLHttpRequest.responseText
con códigos de estado que no sean 200, parece que IE está reemplazando su cuerpo de respuesta por su propio:
Headers (Response)
HTTP/1.1 400 Bad Request
...
Content-Length: 11
Bad Request
Indica que el "contenido" tal como lo trata es el texto de estado de "Solicitud incorrecta", no la respuesta json adecuada (que Chrome lee como contenido de longitud 54, por ejemplo). Esto podría significar que IE está descartando su cuerpo de respuesta (lo dudo, sería increíble) o simplemente no se procesa "correctamente". Intente volcar el resto de su objeto jqXHR
y los argumentos de su controlador de fail
para ver si puede encontrarlo en alguna parte.
Piensa que este es un problema con IIS que intenta usar una respuesta de error personalizada en lugar de enviar el mensaje de error que el controlador está generando.
<system.webServer>
...
<httpErrors existingResponse="PassThrough"></httpErrors>
...
</system.webServer>
O
Response.TrySkipIisCustomErrors = true;
Referencia - https://.com/a/4029197/1304559
Echa un vistazo a esta publicación del blog http://weblog.west-wind.com/posts/2009/Apr/29/IIS-7-Error-Pages-taking-over-500-Errors
Dado que el código de respuesta se establece en 400, IIS reemplaza su contenido con su contenido de página de error personalizado
Su respuesta vuelve con Content-Type: text/html
http header, pero debería ser application/json
. Esto no es un problema en Chrome (y no recibes advertencias de falta de coincidencia en la consola) porque estás confiando en overrideMimeType
... lo cual, lo adivinaste, no es compatible con IE. De hecho, lo siguiente nunca se ejecuta en versiones anteriores de IE:
if (x && x.overrideMimeType) {
return x.overrideMimeType("application/json;charset=UTF-8");
}
Su solución podría ser asegurarse de que el contenido se sirve con el tipo de contenido correcto. Si está familiarizado con las herramientas de manipulación como Burp Suite , puede agregar el encabezado correcto sobre la marcha y ver si eso soluciona el problema. Probablemente evitaría los métodos de AddHeader
como AddHeader
y vería si hay una manera de solucionarlo en un enrutamiento más alto, tal vez, a nivel.