6

I've been playing with Backbone in my Chrome console and running into a cross-domain problem that I can't figure out.

The host I'm connecting to presumably correctly implements CORS because a raw XHR request returns the expected JSON:

var http = new XMLHttpRequest();
http.open('GET', 'http://example.com:3000/entities/item/15.json', true);
http.onreadystatechange = function(evt) { console.log(evt); }
http.send();

(logs 3 XHR progress events on the console with the correct data in the response)

But when I do the following with Backbone the browser doesn't like it:

var Item = Backbone.Model.extend({});
var ItemsCollection = Backbone.Collection.extend({
  model: Item,
  url: 'http://example.com:3000/entities/item/'
});
var items = new ItemsCollection();
items.fetch();

(returns XMLHttpRequest cannot load http://example.com:3000/entities/item/. Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.)

Is there anything I need to do to tell Backbone to work with CORS? This error seems to have come before the browser even made a request, so I don't think it's a server config error.

magneticMonster
  • 2,254
  • 5
  • 28
  • 44
  • You can disable same origin policy in Chrome, [here](http://stackoverflow.com/a/3177718/1344509) explained how to disable it on Chrome. – Ikrom Apr 16 '13 at 15:58
  • Thanks for the tip, but I don't want to disable it (this is designed to run on regular web browsers). – magneticMonster Apr 16 '13 at 16:04
  • Then maybe [this](http://stackoverflow.com/a/6487765/1344509) helps. – Ikrom Apr 16 '13 at 16:18
  • Yep, like I said in the question the CORS works fine on the server side because the browser is able to make requests with a standard XMLHttpRequest. – magneticMonster Apr 16 '13 at 16:39

3 Answers3

8

I hope one of these helps (I didn't try yet):
1. Overriding Backbone.js sync to allow Cross Origin

(function() {
  var proxiedSync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    options || (options = {});
    if (!options.crossDomain) {
      options.crossDomain = true;
    }
    if (!options.xhrFields) {
      options.xhrFields = {withCredentials:true};
    }
    return proxiedSync(method, model, options);
  };
})();

2. Cross domain CORS support for backbone.js

$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    options.crossDomain ={
        crossDomain: true
    };
    options.xhrFields = {
        withCredentials: true
    };
});
Community
  • 1
  • 1
Ikrom
  • 3,635
  • 4
  • 42
  • 68
  • 1
    `xhrFields.withCredentials` will crash in Firefox if you're making synchronous AJAX call, for example loading a template before rendering. Luckily my templates are on the same domain so I could just wrap the above in `if(originalOptions.async !== false)` block – kasztelan Jun 24 '14 at 18:13
  • Where should I add sync method update? In backbone.js OR my script? – dang Dec 11 '14 at 07:40
6

hey you can use something like:

 var PostsCollection = Backbone.Collection.extend({
   initialize: function(models, options) {
     //this.id = options.id;
   },
   url: 'http://myapi/api/get_posts/?count=8',
 });

 posts = new PostsCollection();
 posts.fetch({
   dataType: 'jsonp',
   success : function (data) {
     console.log(data);
   }
 });

the key is we need to use 'jsonp'

heriberto perez
  • 654
  • 6
  • 9
0

It turns out the URLs I was requesting with Backbone were slightly different than those requested via the XHR (they were missing a queryarg). This caused the server to 500, which doesn't have the CORS headers. Chrome didn't show the HTTP request at all in the network tab of the debug panel, so I was extremely confused.

Fixing the 500 on the server made this work again.

magneticMonster
  • 2,254
  • 5
  • 28
  • 44