5

What I want to do is catch a 302 error which means a user is not logged in, and then redirecting that user to the login page of the website. Here's my backbone.js sync override right now:

parentSynchMethod = Backbone.sync
Backbone.sync = (method, model, success, error) -> 
  try
    parentSynchMethod.apply(Backbone, arguments)
  catch error
    window.location.replace("http://localhost:8080/login")

The 302 error is definitely happening, I can see it in the network view when I inspect the page using google chrome. However, when I set a breakpoint, it never goes inside the catch, and the error argument is undefined. Is this because 302 is not a real error(it's yellow when I view the status of the response, instead of a usual red for errors, or am I messing up the code somewhere.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
prashn64
  • 657
  • 1
  • 8
  • 24

1 Answers1

10

The default Backbone.sync doesn't raise an exception when the AJAX request returns an error condition (and yes, 302 is an error), it leaves the error handling to $.ajax. The default sync looks like this:

Backbone.sync = function(method, model, options) {
  // A bunch of bureaucratic setup and what not...

  // Make the request, allowing the user to override any Ajax options.
  return Backbone.ajax(_.extend(params, options));
};

and Backbone.ajax is just $.ajax; note that the above is the current master branch of Backbone, the currently released version uses $.ajax directly.

What you want to do is replace Backbone.sync with something that always forces an error handler like this:

error: (xhr, text_status, error_thrown) ->
    if(xhr.status == 302)
        window.location.replace('http://localhost:8080/login')
    else
        # call the supplied error handler if any

Something like this should do the trick:

parentSynchMethod = Backbone.sync
Backbone.sync = (method, model, options) ->
    old_error = options.error
    options.error = (xhr, text_status, error_thrown) ->
        if(xhr.status == 302)
            window.location.replace('http://localhost:8080/login')
        else
            old_error?(xhr, text_status, error_thrown)
    parentSyncMethod(method, model, options)

If you're using the master branch of Backbone (or reading this after Backbone.ajax is in the released version), then you could replace Backbone.ajax with something that forces an error handler as above and leave Backbone.sync alone.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Thanks for the response, and your solution almost works. I'm getting a 200 status for xhr.status. It's only one application/json file that's throwing the 302 error and the initiator method is jquery.min.js if any of that helps. EDIT: It's also being thrown on a POST. – prashn64 Apr 20 '12 at 14:27
  • @prashn64: I'm not seeing anything get thrown and I can get a 302 in `xhr.status`. You've taken this up elsewhere and getting things sorted out, correct? – mu is too short Apr 20 '12 at 19:42
  • Ahh, yes, I decided to do things a bit differently using google app engine routes, I'll explain my solution next week. – prashn64 Apr 21 '12 at 20:18