2011-09-25 11 views
6

Creo una acción simple de controlador MVC, que toma algunos datos json - luego devuelve verdadero o falso.Publicación de Ajax json al controlador en dominios, "no permitido por" Access-Control-Allow-Headers

[AllowCrossSiteJson] 
    public JsonResult AddPerson(Person person) 
    { 
      //do stuff with person object 
      return Json(true); 
    } 

me llaman desde javascript:

 function saveData(person) { 
      var json = $.toJSON(person); //converts person object to json 
      $.ajax({ 
       url: "http://somedomain.com/Ajax/AddPerson", 
       type: 'POST', 
       dataType: 'json', 
       data: json, 
       contentType: 'application/json; charset=utf-8', 
       success: function (data) { 
        alert("ok"); 
       } 
      }); 
     } 

Todo funciona siempre y cuando estoy en el mismo dominio, pero tan pronto como lo llamo desde otro dominio, me encuentro con problemas.

En el controlador hay un filtro de acción "AllowCrossSiteJson" que establece el encabezado "Access-Control-Allow-Origin" en "*", lo que permite que cualquier origen acceda a la acción del controlador.

public class AllowCrossSiteJsonAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*"); 
     base.OnActionExecuting(filterContext); 
    } 
} 

Sin embargo - y luego me sale este error en Firebug, al llamar a través de dominios:

OPCIONES http://somedomain.com/Ajax/AddPerson?packageId=3 500 (Internal Server Error) XMLHttpRequest no puede cargar http://somedomain.com/Ajax/AddPerson. Campo de encabezado de solicitud Content-Type no está permitido por Access-Control-Allow-Headers.

¿Qué pasa aquí?

He estado buscando posibles soluciones durante horas, y parece ser algo relacionado con jquery usando OPTIONS (no POST como era de esperar).

Si ese es el problema, ¿cómo puedo solucionarlo?

Respuesta

7

Te recomiendo JSONP, es el único navegador realmente cruzado y solución confiable para AJAX de dominio cruzado. Por lo que podría empezar por escribir resultado acción personalizada, que envolverá la respuesta JSON con una devolución de llamada:

public class JsonpResult : ActionResult 
{ 
    private readonly object _obj; 

    public JsonpResult(object obj) 
    { 
     _obj = obj; 
    } 

    public override void ExecuteResult(ControllerContext context) 
    { 
     var serializer = new JavaScriptSerializer(); 
     var callbackname = context.HttpContext.Request["callback"]; 
     var jsonp = string.Format("{0}({1})", callbackname, serializer.Serialize(_obj)); 
     var response = context.HttpContext.Response; 
     response.ContentType = "application/json"; 
     response.Write(jsonp); 
    } 
} 

y luego:

public ActionResult AddPerson(Person person) 
{ 
    return new JsonpResult(true); 
} 

y, finalmente, realizar la cruz llamada AJAX de dominio:

$.ajax({ 
    url: 'http://somedomain.com/Ajax/AddPerson', 
    jsonp: 'callback', 
    dataType: 'jsonp', 
    data: { firstName: 'john', lastName: 'smith' }, 
    success: function (result) { 
     alert(result); 
    } 
}); 
+4

I te amo y quiero tener tus bebés. – Kjensen

+0

¿Esto no funciona solo con las solicitudes de obtención? –

+0

Sí, la implementación jQuery de JSONP solo funciona con solicitudes GET. –

21

Para corregir el error de Access-Control-Allow-Origin, debe incluir el siguiente encabezado en su respuesta:

Access-Control-Allow-Headers: Content-Type

Básicamente, cualquier encabezado "no simple" debe incluirse como una lista delimitada por comas en el encabezado de arriba. Echa un vistazo a la especificación CORS para más detalles:

http://www.w3.org/TR/cors/

"Content-Type" necesita ser incluida porque "application/json" no coincide con los valores definidos aquí:

http://www.w3.org/TR/cors/#terminology

+0

¡Gran respuesta! Mucho mejor que JSONP. –

Cuestiones relacionadas