简体   繁体   中英

CORS pre-flight comes back with Access-Control-Allow-Origin:*, browser still fails request

Triggering an AJAX GET to http://qualifiedlocalhost:8888/resource.json kicks off the expected CORS pre-flight, which looks like it comes back correctly:

Pre-flight OPTIONS request

Request URL:http://qualifiedlocalhost:8888/resource.json
Request Method:OPTIONS
Status Code:200 OK

Request Headers

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, origin, x-requested-with
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:qualifiedlocalhost:8888
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36

Response Headers

Access-Control-Allow-Headers:Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:2
Content-Type:text/plain
Date:Thu, 01 Aug 2013 19:57:43 GMT
Set-Cookie:connect.sid=s%3AEpPytDm3Dk3H9V4J9y6_y-Nq.Rs572s475TpGhCP%2FK%2B2maKV6zYD%2FUg425zPDKHwoQ6s; Path=/; HttpOnly
X-Powered-By:Express

Looking good?

So it should work, right?

But the subsequent request still fails with the error XMLHttpRequest cannot load http://qualifiedlocalhost:8888/resource.json. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin. XMLHttpRequest cannot load http://qualifiedlocalhost:8888/resource.json. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin.

True request

Request URL:http://qualifiedlocalhost:8888/resource.json

Request Headers

Accept:application/json, text/plain, */*
Cache-Control:no-cache
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36
X-Requested-With:XMLHttpRequest

Help!

Maybe it's staring right in front of me. But, any ideas? Just in case it's relevant... I'm using an AngularJS $resource and talking to a CompoundJS server.

change your Access-Control-Allow-Methods: 'GET, POST' to 'GET, POST, PUT, DELETE'

before:

   app.use(function(req, res, next) {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
        next();
    });

After:

app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
    next();
});

I recently had the same issue . The problem is that the Access-Control-Allow-Origin header (and, if you use it, the Access-Control-Allow-Credentials header) must be sent in both the preflight response and the actual response.

Your example has it only in the preflight response.

Is your web server/get function ALSO including the HTTP header: Access-Control-Allow-Origin? I eventually found success with that addition, using AngularJS 1.0.7 and a remote Java servlet. Here is my Java code snippet--no changes were required in AngularJS client:

Servlet:

@Override
protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Send Response
    super.doOptions(request,  response);
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /* ... */
    response.setHeader("Access-Control-Allow-Origin", "*");
}

A more elegant alternative is a servlet filter.

We have been noticing the same issue, where the server is sending the correct CORS headers, but the browser fails because it thinks the CORS requirements are not being met. More interestingly, in our case, it only happens on some AJAX calls in the same browser session, but not all.

Working theory...

Clearing the browser cache solves the problem in our case -- My current working theory is that this has something to do with cookies being set by the cross origin server. I noticed in your scenario, there is a cookie being set as part of the response to the pre-flight OPTIONS request. Have you tried making that server not set any cookies for requests coming from a different origin?

However, we've noticed that in some cases, the problem re-appeared after resetting the browser. Also, running the browser in in-private mode causes the problem to go away, pointing to some problem to do with what's in the browser cache.

For reference, here is my scenario (I almost posted this as a new question in SO, but putting it here instead):

We ran into a bug where some CORS GET requests made via jQuery.ajax were failing. In a given browser session, we see the pre-flight OPTIONS request go through, followed by the actual request. In the same session, some requests go through and others fail.

The sequence of requests and responses in the browser network console look like below:

First the OPTIONS pre-flight request

OPTIONS /api/v1/users/337/statuses
HTTP/1.1 Host: api.obfuscatedserver.com 
Connection: keep-alive 
Access-Control-Request-Method: GET 
Origin: http://10.10.8.84:3003 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
Access-Control-Request-Headers: accept, origin, x-csrf-token, auth 
Accept: */* Referer: http://10.10.8.84:3003/ 
Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8

Which gets a response like,

HTTP/1.1 200 OK 
Date: Tue, 06 Aug 2013 19:18:22 GMT 
Server: Apache/2.2.22 (Ubuntu) 
Access-Control-Allow-Origin: http://10.10.8.84:3003 
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT 
Access-Control-Max-Age: 1728000 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: accept, origin, x-csrf-token, auth 
X-UA-Compatible: IE=Edge,chrome=1 
Cache-Control: no-cache 
X-Request-Id: 4429c4ea9ce12b6dcf364ac7f159c13c 
X-Runtime: 0.001344 
X-Rack-Cache: invalidate, pass 
X-Powered-By: Phusion 
Passenger 4.0.2 
Status: 200 OK 
Vary: Accept-Encoding
Content-Encoding: gzip

Then the actual GET request,

GET https://api.obfuscatedserver.com/api/v1/users/337
HTTP/1.1 
Accept: application/json, text/javascript, */*; q=0.01 
Referer: http://10.10.8.84:3003/ 
Origin: http://10.10.8.84:3003 
X-CSRF-Token: xxxxxxx 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 
auth: xxxxxxxxx

Which gets an error in the browser console like,

XMLHttpRequest
  cannot load https://api.obfuscatedserver.com/api/v1/users/337.
  Origin http://10.10.8.84:3003 is not allowed by Access-Control-Allow-Origin.

Additional Debugging

I can replay the same sequence via curl, and I see valid responses coming from the server. ie they have the expected CORS headers that should let the requests go through.

Running the same scenario in an in-private / incognito browser window did not reproduce the problem. This lead me to try clearing the cache, and that made the problem go away too. But after a while, it came back.

The issue was reproducing on iPhone safari as well as on Chrome on OSX desktop.

What I really need help with

I'm suspecting there are some cookies set in the cross-origin domain that are getting involved here and potentially exposing a bug in the browser. Are there tools or breakpoints I can set in the browser (native stack?) to try and debug this further? A breakpoint in the code that evaluates the CORS policy would be ideal.

Looks like your response to 'options' is working fine. The problem seems to be in the 'get' response.

You'll want to have your 'get' response return the same CORS headers as the 'options' response.

In particular, 'get' response should include

Access-Control-Allow-Headers:Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:*

use cors module to avoid the problem

var cors = require('cors')

var app = express()
app.use(cors())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM