CORS cross-domain support for backbone.js

I am trying to implement cross-domain configuration for my base application.

my server (express.js) allows cross domains and credentials:

var allowCrossDomain = function(req, res, next) { var allowedHost = [ 'http://localhost:3001', 'http://localhost:7357' ]; if(allowedHost.indexOf(req.headers.origin) !== -1) { res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Origin', req.headers.origin) res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'); next(); } else { res.send({auth: false}); } } app.configure(function(){ .... app.use(allowCrossDomain); .... }); 

my client (backbone.js) is configured to accept cross-domain:

 define(["backbone", "jquery", "underscore"], function (BB, $, _) { return BB.Model.extend({ idAttribute: "_id", initialize: function () { var that = this; $.ajaxPrefilter( function( options, originalOptions, jqXHR ) { options.crossDomain ={ crossDomain: true }; options.xhrFields = { withCredentials: true }; }); } }); }); 

Now when I check my code (say, a POST request), I have a very special behavior:

 var contacts = new Contacts; contacts.create({'name': 'my name'}); 

The browser returns this message:

OPTIONS ... 404 (not found) jquery.js: 8419

Does this completely confuse me as the OPTIONS http method is not supported by the backbone system?

+1
source share
1 answer

Most likely, your express routes indicate only GET and / or POST methods. For instance,

 app.post('/some/api/method', function(req, res) { ... }); 

This means that you only defined a route handler for POST to / some / api / method, and queries using any other method (for example, GET or OPTIONS ) will return 404.

In certificates (such as sending your own HTTP headers), XHR requests to URLs with cross-URLs using CORS require the browser to issue OPTIONS first to check if requests for cross-domain requests are allowed. Only if the OPTIONS request succeeds (HTTP 200 with CORS headers) does the browser execute the actual request.

Since you only defined the POST route on your server, the OPTIONS request fails and the browser does not make the request. You need to correctly answer the OPTIONS request:

 app.options('/some/api/method', function(req, res) { // At this point, the `allowCrossDomain()` middleware will already have // taken care of the CORS stuff, so just return OK. res.send(200); }); 

Now the preflight OPTIONS check will pass, so a real request will be made to the POST handler.


Bonus comments regarding your code:

  • Performance Improvements:
    • Use the object to search and verify the source, not the array. Using indexOf requires a slow iteration of the array on every request, where using the object allows you to quickly perform a search. (Remember that JavaScript objects store their keys in a data structure similar to a dictionary.)
    • Define allowedHosts outside the check function - they do not change, so there is no need to create a new object each time allowCrossDomain is allowCrossDomain (garbage collection is required).
  • You should probably send a response code to the failed HTTP code if the cross-origin error failed.

 var allowedHost = { 'http://localhost:3001': true, 'http://localhost:7357': true }; var allowCrossDomain = function(req, res, next) { if(allowedHost[req.headers.origin]) { res.header('Access-Control-Allow-Credentials', true); res.header('Access-Control-Allow-Origin', req.headers.origin) res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.header('Access-Control-Allow-Headers', 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'); next(); } else { res.send(403, {auth: false}); } } 
+7
source

All Articles