jQuery.getJSON - Access-Control-Allow-Origin Issue

I'm jusing jQuery's $.getJSON() function to return a short set of JSON data.

I've got the JSON data sitting on a url such as example.com. I didn't realize it, but as I was accessing that same url, the JSON data couldn't be loaded. I followed through the console and found that XMLHttpRequest couldn't load due to Access-Control-Allow-Origin.

Now, I've read through, a lot of sites that just said to use $.getJSON() and that would be the work around, but obviously it didn't work. Is there something I should change in the headers or in the function?

Help is greatly appreciated.


It's simple, use $.getJSON() function and in your URL just include

callback=?

as a parameter. That will convert the call to JSONP which is necessary to make cross-domain calls. More info: http://api.jquery.com/jQuery.getJSON/


You may well want to use JSON-P instead (see below). First a quick explanation.

The header you've mentioned is from the Cross Origin Resource Sharing standard. Beware that it is not supported by some browsers people actually use, and on other browsers (Microsoft's, sigh) it requires using a special object (XDomainRequest) rather than the standard XMLHttpRequest that jQuery uses. It also requires that you change server-side resources to explicitly allow the other origin (www.xxxx.com).

To get the JSON data you're requesting, you basically have three options:

  1. If possible, you can be maximally-compatible by correcting the location of the files you're loading so they have the same origin as the document you're loading them into. (I assume you must be loading them via Ajax, hence the Same Origin Policy issue showing up.)

  2. Use JSON-P, which isn't subject to the SOP. jQuery has built-in support for it in its ajax call (just set dataType to "jsonp" and jQuery will do all the client-side work). This requires server side changes, but not very big ones; basically whatever you have that's generating the JSON response just looks for a query string parameter called "callback" and wraps the JSON in JavaScript code that would call that function. E.g., if your current JSON response is:

    {"weather": "Dreary start but soon brightening into a fine summer day."}
    

    Your script would look for the "callback" query string parameter (let's say that the parameter's value is "jsop123") and wraps that JSON in the syntax for a JavaScript function call:

    jsonp123({"weather": "Dreary start but soon brightening into a fine summer day."});
    

    That's it. JSON-P is very broadly compatible (because it works via JavaScript script tags). JSON-P is only for GET, though, not POST (again because it works via script tags).

  3. Use CORS (the mechanism related to the header you quoted). Details in the specification linked above, but basically:

    A. The browser will send your server a "preflight" message using the OPTIONS HTTP verb (method). It will contain the various headers it would send with the GET or POST as well as the headers "Origin", "Access-Control-Request-Method" (e.g., GET or POST), and "Access-Control-Request-Headers" (the headers it wants to send).

    B. Your PHP decides, based on that information, whether the request is okay and if so responds with the "Access-Control-Allow-Origin", "Access-Control-Allow-Methods", and "Access-Control-Allow-Headers" headers with the values it will allow. You don't send any body (page) with that response.

    C. The browser will look at your response and see whether it's allowed to send you the actual GET or POST. If so, it will send that request, again with the "Origin" and various "Access-Control-Request-xyz" headers.

    D. Your PHP examines those headers again to make sure they're still okay, and if so responds to the request.

    In pseudo-code (I haven't done much PHP, so I'm not trying to do PHP syntax here):

    // Find out what the request is asking for
    corsOrigin = get_request_header("Origin")
    corsMethod = get_request_header("Access-Control-Request-Method")
    corsHeaders = get_request_header("Access-Control-Request-Headers")
    if corsOrigin is null or "null" {
        // Requests from a `file://` path seem to come through without an
        // origin or with "null" (literally) as the origin.
        // In my case, for testing, I wanted to allow those and so I output
        // "*", but you may want to go another way.
        corsOrigin = "*"
    }
    
    // Decide whether to accept that request with those headers
    // If so:
    
    // Respond with headers saying what's allowed (here we're just echoing what they
    // asked for, except we may be using "*" [all] instead of the actual origin for
    // the "Access-Control-Allow-Origin" one)
    set_response_header("Access-Control-Allow-Origin", corsOrigin)
    set_response_header("Access-Control-Allow-Methods", corsMethod)
    set_response_header("Access-Control-Allow-Headers", corsHeaders)
    if the HTTP request method is "OPTIONS" {
        // Done, no body in response to OPTIONS
        stop
    }
    // Process the GET or POST here; output the body of the response
    

    Again stressing that this is pseudo-code.