CORS Access-Control-Allow-Origin despite correct headers
Solution 1
So I was being mislead by the response from going to the URL, and in fact the problem was that when doing the ajax request, I was getting a 403 (only revealed in firefox not chrome) error due to csrf protection.
Solution 2
You have to implement a "pre-flighted" request and response because your situation counts as a "not so simple" request. Basic CORS, that only requires the Origin header, can only have content types of "application/x-www-form-urlencoded", "multipart/form-data", and "text/plain". Since you return "application/json", you don't meet this requirement.
I don't know anything about Django, but I found it easier to implement CORS support outside of my application through the use of a Tomcat filter. It looks like you can do the same thing with Django.
2013-08-11: It looks like the GitHub repo is no longer with us. But the Django package looks to still be available at https://pypi.python.org/pypi/django-cors/0.1
Solution 3
I was using the excellent django-cors-headers library and ran into this problem as well. For me, the solution was to add 'accept-encoding' to the default CORS_ALLOW_HEADERS tuple.
Comments
-
zenna almost 2 years
I am trying to set up simple Cross-Origin Resource Sharing using jQuery (1.7.1) powered ajax on the client and apache served python (django) server. According to all the instructions I have read my headers are set correctly, but I keep getting the following error:
XMLHttpRequest cannot load http://myexternaldomain.com/get_data. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin.
The header being I am trying to (I am not sure it is even getting past the browser) send is:
Request URL:http://myexternaldomain.com/get_data Accept:application/json, text/javascript, */*; q=0.01 Origin:http://localhost:8080 Referer:http://localhost:8080/static/js/test-zetta.html User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11
The javascript code is
var request = $.ajax({ url : "http://myexternaldomain.com/get_data", type : "POST", dataType : "json", crossDomain : true });
Note that
origin
is set correctly. The server adds the headerAccess-Control-Allow-Origin = *
using the following python codedef process_response(self, response): if response.has_header('Access-Control-Allow-Origin'): return response response['Access-Control-Allow-Origin'] = '*' return response def get_orders(request): """ Tell worker what to do """ response_data = {} response_data['action'] = 'probe' response = process_response(HttpResponse(json.dumps(response_data), mimetype="application/json")) return response
If I visit the address directly, it appears to confirm that the header is being set correctly
Access-Control-Allow-Origin:* Content-Type:application/json Date:Thu, 08 Mar 2012 05:06:25 GMT Server:Apache/2.2.20 (Ubuntu) Transfer-Encoding:chunked
However in the cross domain setting it always fails (tried both chrome and firefox). I've tried implementing the code exactly as per the selected answer to this question, but get the same error
Update
I am quite sure that the problem is server side, as I have managed to get my ajax calls working with a different public CORS enabled server. When I compare the headers coming back from this public server, and the ones returned from mine (when I test from same domain), I cannot see any major difference which could account for difference (see below).
One subtlety that I excluded, which may or may be important is that the actual domain is an amazon domain of multiple subdomains. The real address is http://ec2-23-20-27-108.compute-1.amazonaws.com/get_orders , feel free to probe it to see what I am doing wrong.
From Public server
Access-Control-Allow-Origin:* Connection:Keep-Alive Content-Encoding:gzip Content-Length:622 Content-Type:text/html Date:Thu, 08 Mar 2012 15:33:20 GMT Keep-Alive:timeout=15, max=99 Server:Apache/2.2.14 (Ubuntu) Vary:Accept-Encoding X-Powered-By:Perl/5.8.7, PHP/4.4.0
From my server - (not working cross domain)
Access-Control-Allow-Origin:* Content-Encoding:gzip Content-Type:text/plain Date:Thu, 08 Mar 2012 15:32:24 GMT Server:Apache/2.2.20 (Ubuntu) Transfer-Encoding:chunked Vary:Accept-Encoding
-
JW. about 12 yearsPretty sure the browser is supposed to take care of the preflight request....at least Chrome does.
-
devdavid about 12 yearsBut the server has to recognize it. His script only responds to basic requests by adding the Origin header to every request.
-
zenna about 12 yearsI tried making the request simple, by making my data a simple string, expecting plain text in the $.ajax call and returning mimetype='text/plain' in the python, but still get the same errors.
-
zenna about 12 yearsI've also managed to make it work with a public cors enabled server, so can be pretty confident in that my problem is server side.
-
devdavid about 12 yearsYes, that is exactly what I was saying. Your server side script is not handling the pre-flight type of requests. Based on the code you have provided, your script will only work with basic CORS requests.
-
devdavid about 12 yearsFurther, if you return the string '{"foo":"bar"}' to jQuery as "text/plain", it might fail because it recognizes the string as JSON. I'm not sure about that one, though.
-
orokusaki about 11 yearsOh man, thanks so much. I had my
enable_cors
wrapper around mycsrf_exempt
wrapper, needed to reverse them. I was like, WTF... -
Adam Tuttle almost 11 yearsI can't overstate the awesomeness of this answer. It's dead-on.