Ajax json post to Controller across domains, "not allowed by" Access-Control-Allow-Headers
Solution 1
I'd recommend you JSONP, it's the only really cross browser and reliable solution for cross domain AJAX. So you could start by writing a custom action result that will wrap the JSON response with a callback:
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);
}
}
and then:
public ActionResult AddPerson(Person person)
{
return new JsonpResult(true);
}
and finally perform the cross domain AJAX call:
$.ajax({
url: 'http://somedomain.com/Ajax/AddPerson',
jsonp: 'callback',
dataType: 'jsonp',
data: { firstName: 'john', lastName: 'smith' },
success: function (result) {
alert(result);
}
});
Solution 2
To fix the Access-Control-Allow-Origin error, you need to include the following header in your response:
Access-Control-Allow-Headers: Content-Type
Basically, any "non-simple" header needs to be included as a comma-delimited list in the header above. Check out the CORS spec for more details:
"Content-Type" needs to be included because "application/json" does not match the values defined here:
http://www.w3.org/TR/cors/#terminology
Related videos on Youtube
Kjensen
Updated on June 05, 2022Comments
-
Kjensen almost 2 years
I create a simple MVC Controller action, that takes some json data - then return true or false.
[AllowCrossSiteJson] public JsonResult AddPerson(Person person) { //do stuff with person object return Json(true); }
I call it from 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"); } }); }
Everything works as long as I am on the same domain, but as soon as I call it from another domain, I run into problems.
On the controller is an action filter "AllowCrossSiteJson" that sets the header "Access-Control-Allow-Origin" to "*", allowing any origin to access the controller action.
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*"); base.OnActionExecuting(filterContext); } }
However - I then get this error in firebug, when calling across domains:
OPTIONS http://somedomain.com/Ajax/AddPerson?packageId=3 500 (Internal Server Error) XMLHttpRequest cannot load http://somedomain.com/Ajax/AddPerson. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
What is wrong here?
I have been looking through possible solutions for hours, and it seems to be something to do with jquery using OPTIONS (not POST as I would expect).
If that is indeed the problem, how can I fix that?
-
Kjensen over 12 yearsI love you and want to have your babies.
-
Darin Dimitrov almost 12 yearsYes, the jQuery implementation of JSONP works only with GET requests.
-
eCommerce Guru over 11 yearsGreat answer! Much better than JSONP.