CORS Access-Control-Allow-Origin despite correct headers

14,249

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.

Share:
14,249
zenna
Author by

zenna

Electronic Engineer, Biomedical Engineer, C++/CUDA

Updated on June 04, 2022

Comments

  • zenna
    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 header Access-Control-Allow-Origin = * using the following python code

    def 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.
    JW. about 12 years
    Pretty sure the browser is supposed to take care of the preflight request....at least Chrome does.
  • devdavid
    devdavid about 12 years
    But the server has to recognize it. His script only responds to basic requests by adding the Origin header to every request.
  • zenna
    zenna about 12 years
    I 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
    zenna about 12 years
    I'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
    devdavid about 12 years
    Yes, 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
    devdavid about 12 years
    Further, 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
    orokusaki about 11 years
    Oh man, thanks so much. I had my enable_cors wrapper around my csrf_exempt wrapper, needed to reverse them. I was like, WTF...
  • Adam Tuttle
    Adam Tuttle almost 11 years
    I can't overstate the awesomeness of this answer. It's dead-on.