Why does No 'Access-Control-Allow-Origin'

2019-07-25 10:51发布

问题:

I'm building a RESTful service on a JAX-RS server and some clients that will be attached to it.

The hour came to start testing the endpoints on the clients and I tried first on JavaScript since until now, it has been very easy for me to make requests to third party resources with this code:

function httpGet(theUrl){
            var xmlHttp = new XMLHttpRequest();
            xmlHttp.open( "GET", theUrl, false );
            xmlHttp.send( null );
            return xmlHttp.responseText;
}

I know I shouldn't do synchronous requests but that's off topic.

On Firefox, the error I get is:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://someurl.com/someresource/. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

The requests don't work both on my local server and on the deployment server.

I've found that most solutions to this problem have to do something with setting a header Access-Control-Allow-Origin: *. I've tried this and it hasn't worked for me.

At first I thought it was a problem with my server configuration, but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy. Is this correct? If it's correct, why does the exact same code as above, with no Access-Control-Allow-Headers: *, works for third party services (Google, Facebook, etc.)?

Is there a whitelist of sites that are always allowed to break the Same Origin Policy?

If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?

回答1:

At first I thought it was a problem with my server configuration

It is.

but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy.

That's true. The browser is disallowing the request per the SOP because your server isn't configured to allow cross-origin requests.

It's much more than just passing back a single header. Full details in the spec, but basically it comes down to:

  1. Responding to OPTIONS requests, not just GET, POST, and so on.

  2. Responding with all of the necessary headers.

  3. Responding with the correct values for those headers.

The headers you'll have to send back are at least:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

and you may also need Access-Control-Allow-Credentials. The values you need to supply for these are usually derived from the headers with similar (but slightly different) names that accompany the request.

You must supply the headers both in response to the OPTIONS call (if there is one), and also the subsequent GET or POST etc. call.

If it's correct, why does the exact same code as above, with no Access-Control-Allow-Headers: *, works for third party services (Google, Facebook, etc.)?

The browser fills in the request headers automatically; what's different is the server responding to the request.

Is there a whitelist of sites that are always allowed to break the Same Origin Policy?

No, of course not.

If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?

The above.

Here's some pseudocode for the server side granting access via CORS (it's written in JavaScript, since I know you're familiar with JavaScript, but it is pseudocode, and you need to do this on your server):

var origin, method, headers;
origin = getRequestHeader("Origin");
if (origin /* and you want to grant access to it */) {
    addResponseHeader("Access-Control-Allow-Origin", origin);
    method = getRequestHeader("Access-Control-Request-Method");
    if (method) {
        // Note the request header is singular, but the response header is plural
        addResponseHeader("Access-Control-Allow-Methods", method);
    }
    headers = getRequestHeader("Access-Control-Request-Headers");
    if (headers) {
        addResponseHeader("Access-Control-Allow-Headers", headers);
    }
    if (/* You want to allow the origin to provide credentials and cookies*/) {
        addResponseHeader("Access-Control-Allow-Credentials", "true");
    }
}


回答2:

At first I thought it was a problem with my server configuration, but now I think it's the browser that is not letting me execute the request because of the Same Origin Policy. Is this correct?

By default, the browser will enforce the Same Origin Policy and block your JavaScript from accessing the data.

The configuration of the server you are making the request to can set CORS headers (including Access-Control-Allow-Origin and Access-Control-Allow-Headers) to tell the browser not to enforce the Same Origin Policy for that request.

Is there a whitelist of sites that are always allowed to break the Same Origin Policy?

No

If the answer to the last question is no, then they must have some specific configutation on their server side code to allow Cross Origin communications to happen. What could this configuration be?

The configuration sets the response headers that are described in the error message you quoted.