在每个Backbone HTTP请求之前检查一些同步

时间:2013-07-01 13:52:05

标签: javascript jquery ajax backbone.js marionette

在我的Backbone / Marionette应用程序的每个经过身份验证的请求(GET,POST等)中,我必须附加一个accessToken。

我将此accessToken和expireDate存储在localStorage中。

要检查accessToken是否过期,我调用此方法:user.checkToken()。 如果已过期,则该方法会使用POST请求将accessToken更新到我的后端。

我应该把这张支票放在哪里?我的意思是,申请的哪一部分?

我是否应该重写 Backbone.sync 方法或使用 ajax.setup “beforeSend”?

提前感谢您的建议/想法。

2 个答案:

答案 0 :(得分:2)

覆盖模型的sync()函数并执行您需要执行的任何操作。例如:

var MyModel = Backbone.Model.extend({
  sync: function() {
    // Put your code here

    Backbone.Model.prototype.sync.apply(this, arguments);
  }
});

编辑#1:

不知道从哪里得到user(以及其他变量),但在这里:

var MyModel = Backbone.Model.extend({
  sync: function() {
    user.checkToken().done(_.bind(function(){
       Backbone.Model.prototype.sync.apply(this, [ method, model, options ]);
     });
  }, this);
});

答案 1 :(得分:2)

Backbone使用jQuery(请参阅可能适用于Zepto的解决方案的注释)来获取ajax请求,因此您可以使用(如Edward所建议的)jQuery.ajaxPrefilter

我为这项任务做了一点测试,让我知道是否有任何问题:

function tokenIsExpired() {
    return true;
}

function createPromiseFunction(method, jqXHRsource, jqXHR) {
    return function() {
        jqXHRsource[method] = function(f) {
            if (f) {
                jqXHR[method] = function() {
                    f.apply(this, arguments);
                };
            }

            return this;
        };
    }
}

function updateToken() {
    return $.ajax({
        url: '',
        method: 'GET',
        data: {some:'data', here:'yes'},
        success: function() {
            // update the token sir
            console.log('token call done')
        },
        skipTokenCheck: true // required
    });
}


$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
    /*
     * check if token is expired every time a new ajax request is made
     * if it is expired, aborts the current requests, updated the token
     * and eventually does the original request again.
     */

    if (!options.skipTokenCheck && tokenIsExpired()) {
        // at this point no callback should have be added to the promise object

        var methodsNames = [
            'done',
            'always',
            'fail',
            'progress',
            'then'
        ];

        var methods = {};

        // copy the callbacks when they're added to the old request

        for (var i = 0; i < methodsNames.length; i++) {
            var name = methodsNames[i];

            createPromiseFunction(name, jqXHR, methods)();
        };

        jqXHR.abort();

        // TODO: error checks
        updateToken().done(function() {
            console.log('done');
            var newReq = $.ajax($.extend(originalOptions, {skipTokenCheck: true}));

            for (var i = 0; i < methodsNames.length; i++) {
                var name = methodsNames[i];
                var f = methods[name];

                if (f) {
                    newReq[name](f);
                }
            };
        });
    }
});

var p = $.get('.');

p.done(function() { console.log(arguments); }).fail(function() {
    console.log('fail');
});

看起来ajaxPrefilter不适用于Zepto。或者,您可以使用ajaxBeforeSend事件。

  

在beforeSend函数中返回false将取消请求。

应该很容易调整我上面发布的代码。