Why does an OPTIONS request fail when the answer to the follow up request is a 204?
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"):
- Preflight request (details omitted)
- "Set the cross-origin request status to preflight complete."
- "This is the actual request. (...) observe the request rules below while making the request."
-
If the response has an HTTP status code of 301, 302, 303, or 307Not applicable -
If the end user cancels the requestNot applicable -
If there is a network errorNot applicable - Otherwise
Perform a resource sharing check. If it returns fail, apply the cache and network error steps.
-
Your request already fails at the first step of the resource sharing check:
- If the response includes zero or more than one
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.
GeorgieF
Updated on July 09, 2022Comments
-
GeorgieF almost 2 years
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?