17

I have a Backbone Collection object with the following URL "http://localhost:8080/api/menu/1/featured". I am trying to perform a fetch operation to retrieve the collection from the url and parse it. However, on the server side, the method type that I see for this request is OPTIONS. The server is only suppose to support GET method. I am not sure how Backbone is figuring out what method type to use, and why it changes to OPTIONS method type randomly sometimes. I am using a Node.js server to process the request. This code below is pretty much what I did.

var FeaturedCollection = Backbone.Collection.extend({
    model:FeaturedContent,
    url:function () { return url_featured; },
    parse:function (response) {
        console.log(response);
        return response;
    }
});

var featuredCollection = new FeaturedCollection();
featuredCollection.fetch();

Please help, thanks!

Jeffrey Chen
  • 989
  • 2
  • 9
  • 14

4 Answers4

21

It's been awhile, but I remember coming across this before. There's two things this could be: Backbone by default tried to do RESTful API calls to your backend, this means GET, POST, PUT, and DELETE.

Many backends weren't built with real REST support and only support GET and POST. When Backbone sends a PUT or DELETE command your browser (not Backbone) automatically sends an OPTIONS request first to see if it's allowed to make these kinds of requests. If your server answers improperly this call will fail and probably Backbone won't do anything.

To get around this set Backbone.emulateHTTP = true; Or have your server properly answer OPTIONS calls. See the documentation for more info: http://backbonejs.org/#Sync-emulateHTTP

The other issue is that you're making ajax requests cross-domain / sub-domain and you need to properly enable CORS. This also includes properly answering OPTIONS requests.

Mauvis Ledford
  • 35,240
  • 13
  • 77
  • 84
  • I don't think this answer is right. I have the same issue with the save() method + CORS. My server can handle CORS calls properly, I tried out with $.ajax and an external REST interface tester too. Now I send POST call with model.save(), the Access-Control-Request-Method is POST, but the method is OPTIONS, so my server is confused and sends 404 header back.. I use PHP SLIM on server side. – inf3rno May 17 '13 at 00:49
  • Just because it didn't work for you didn't mean it didn't help other people. Sorry, I don't know much about your setup it could be a number of other things. – Mauvis Ledford May 17 '13 at 18:25
  • 1
    By CORS calls, u have a preflight OPTIONS call, and if you don't respond well to Access-Control-Request-* headers with Access-Control-Allow-* headers, then your original request will fail. That was my problem, but I read now that you wrote the same, so excuse me for vote down! – inf3rno May 19 '13 at 04:41
6

I had the exact same problem as OP - using Backbone and NodeJS to save data via a CORS POST request would constantly send an OPTIONS http request header, and not trigger the POST request at all.

Apparently CORS with requests that will "cause side-effects on user data" will make your browser "preflight" the request with the OPTIONS request header to check for approval, before actually sending your intended HTTP request method. https://developer.mozilla.org/en-US/docs/HTTP_access_control#Overview

This thread was what solved my problem - How to allow CORS?

The poster used some middleware to approve PUT/GET/POST/DELETE requests like so -

res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
...
next();

and the next(); would allow the OPTIONS check to continue on to the POST request.

Worked like a dream for me, hope it helps someone else too.

Community
  • 1
  • 1
soupasouniq
  • 193
  • 1
  • 9
  • How about doing something like: `if request.method == "OPTIONS" return 200` to tell front end **OPTIONS** request can be processed? I'm using a Python backend and not sure if there is an equivalent of **next()**. – benjaminz Apr 13 '16 at 12:26
1

Backbone.js maps CRUD methods to HTTP. Taken from Backbone's source code:

var methodMap = {
  'create': 'POST',
  'update': 'PUT',
  'delete': 'DELETE',
  'read':   'GET'
};
Backbone.sync = function(method, model, options) {
   var type = methodMap[method];

Probably the problem resides on your node.js backend.

eabait
  • 1,126
  • 2
  • 10
  • 15
0

What version of backbone are you using? I had exactly the same issue, but then realised I had been using an old version of backbone (0.3.3) in a tutorial. Upgraded the link to the latest backbone.js (0.9.2) and underscore.js(1.3.3) and it sends as a GET.