Ajax json post to Controller across domains, "not allowed by" Access-Control-Allow-Headers

19,068

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:

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

"Content-Type" needs to be included because "application/json" does not match the values defined here:

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

Share:
19,068

Related videos on Youtube

Kjensen
Author by

Kjensen

Updated on June 05, 2022

Comments

  • Kjensen
    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
    Kjensen over 12 years
    I love you and want to have your babies.
  • Darin Dimitrov
    Darin Dimitrov almost 12 years
    Yes, the jQuery implementation of JSONP works only with GET requests.
  • eCommerce Guru
    eCommerce Guru over 11 years
    Great answer! Much better than JSONP.