9
votes

Got a django dev server running on localhost:8000 and a nodejs server on localhost:3000. I want to import json into the nodejs server but I'm getting this error:

XMLHttpRequest cannot load http://127.0.0.1:8000/api/presentation/?format=json. Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin

This is my first foray into cross-domain fun so I'm WAY out of my depth.

I've added this to my routes in node (expressjs).

app.all('/', function(req, res){
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.render('index', {
    title: '...'
  });
});

What am I missing / doing wrong?

6

6 Answers

9
votes

The data provider needs to set a policy for cross domain request (not the client, as your expressjs snippets suggests).

Someone posted a gist with a simple Django middleware taking care of injecting the needed headers:

Middlware to allow's your django server to respond appropriately to cross domain XHR (postMessage html5 API).

6
votes

https://gist.github.com/426829 - This snippet was really useful however doing POST using backbone to django server i had to match Access-Control-Request-Headers header on request with Access-Control-Allow-Headers on response.

coffee:

auth = (xhr) ->
xhr['xhrFields']= {withCredentials: true}
xhr.setRequestHeader('Access-Control-Allow-Credentials', 'true' )
xhr.header('Access-Control-Allow-Origin', "*")
xhr.header('Access-Control-Allow-Methods', 'GET,POST,PUT,HEAD,DELETE,OPTIONS')
xhr.header('Access-Control-Allow-Headers', 'Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control')  

python: https://gist.github.com/426829 with one extra line

def process_request(self, request):

    if 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' in request.META:
        response = http.HttpResponse()
        response['Access-Control-Allow-Origin']  = XS_SHARING_ALLOWED_ORIGINS
        response['Access-Control-Allow-Methods'] = ",".join( XS_SHARING_ALLOWED_METHODS )
        response['Access-Control-Allow-Headers'] = "Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control"
        return response

    return None          

Hope this is useful!

1
votes

You could have also used JSONP like

http://127.0.0.1:8000/api/presentation/?format=jsonp 
1
votes

This gist is a TastyPie resource base class. Any resource subclassing this will be cross-domain accessable.

It's similar to others out there but will add CORS headers to all respones a TastyPie resource may give. This includes error responses and ImmediateHttpResponse exceptions

from tastypie.resources import Resource
from tastypie.exceptions import ImmediateHttpResponse
from django.http import HttpResponse


class CorsResource(Resource):

    """ adds CORS headers for cross-domain requests """

    def patch_response(self, response):

        allowed_headers = ['Content-Type', 'Authorization']

        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Headers'] = ','.join(allowed_headers)
        return response

    def dispatch(self, *args, **kwargs):
        """ calls super and patches resonse headers
            or
            catches ImmediateHttpResponse, patches headers and re-raises
        """

        try:
            response = super(CorsResource, self).dispatch(*args, **kwargs)
            return self.patch_response(response)
        except ImmediateHttpResponse, e:
            response = self.patch_response(e.response)
            # re-raise - we could return a response but then anthing wrapping
            # this and expecting an exception would be confused
            raise ImmediateHttpResponse(response)

    def method_check(self, request, allowed=None):
        """ Handle OPTIONS requests """
        if request.method.upper() == 'OPTIONS':

            if allowed is None:
                allowed = []

            allows = ','.join([s.upper() for s in allowed])

            response = HttpResponse(allows)
            response['Allow'] = allows
            raise ImmediateHttpResponse(response=response)

        return super(CorsResource, self).method_check(request, allowed)
1
votes

There is a friendly and configurable Django module for this: django-cors-headers

0
votes

Setting dataType: 'text' instead of 'jsonp' in the ajax POST code worked for me.