Reputation: 2727
I'm building a Backbone.js based app and face a strange issue.
At a certain point the app requests a collection resource and inside Chrome (and Safari) I get an error like that:
XMLHttpRequest cannot load http://api.mydomain.net/v1/foos/00000d/bars/000014/boots Origin http://localhost:3501 is not allowed by Access-Control-Allow-Origin.
Ok, CORS issue I thought and blamed my API. Then requested this very resource via CURL:
curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XOPTIONS 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots'
HTTP/1.1 200 OK
Status: 200
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-Auth-Token
Content-Length: 0
looks good, now the GET:
curl -i -H'Accept: application/json' -H'X-Auth-Token: pAWp5hrCmXA83GgFzgHC' -XGET 'http://api.mydomain.net/v1/foos/00000d/bars/000014/boots'
HTTP/1.1 204 No Content
Status: 204
Cache-Control: no-cache
Content-Length: 0
Content-Type: text/plain
In case I request boots collection that contain at least one object, everything works fine. The CORS headers my server responds with arr totally fine as I think. So why do the browsers report a cross origin resource problem?
Is it due to the content type text/plain
of my 204 responses?
Preflight (OPTIONS) request in dev tools:
Request headers of aborted response:
Upvotes: 10
Views: 28037
Reputation: 349012
You have to also include the Access-Control-Allow-Origin
in the response headers of the second request. That's not a client-side issue, but a backend one.
This behaviour is in accordance with the CORS specification, applied in the following explanation (section 7.1.5 "Cross-Origin Request with Preflight"):
Your request already fails at the first step of the resource sharing check:
Access-Control-Allow-Origin
header values, return fail and terminate this algorithm.I provide a simple NodeJS example illustrating your problem.
Your current backend behaves like:
require('http').createServer(function(request, response) {
if (request.method == 'OPTIONS') { // Handle preflight
response.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "X-Foo"
});
} else { // Handle actual requests
response.writeHead(204, {
//"Access-Control-Allow-Origin": "*"
});
}
response.end();
}).listen(12345);
Now, make the request and experience a failure:
var x = new XMLHttpRequest;
x.open('GET', 'http://localhost:12345');
x.setRequestHeader('X-Foo','header to trigger preflight');
x.send();
Go back to the code I provided, and enable the Access-Control-Allow-Origin
header in the response, and test again. Your request will now succeed.
Upvotes: 16