7

我需要在来自服务器的所有响应中捕获一个可能的登录页面,因此我已全局覆盖 Backbone.sync,以便在传递它们之前检查所有错误。

Backbone.originalSync = Backbone.sync;

Backbone.sync = function (method, model, options) {
    var originalSuccess, originalError;
    console.log("sync override...");
    // remember original success so we can call it if user logs in successfully
    originalSuccess = options.success;
    // proxy the error callback to first check if we get a login page back
    originalError = options.error;
    options.error = function (model, xhr, options) {
        if (xhr.status === 200 && xhr.responseText === "") {
            // parse error from empty response (jq1.9 invalid json, ok)
            originalSuccess(model, xhr, options);
        } else {
            console.log("Sync error " + statusTxt + ", " + thrown.message);
            if (xhr.status === 200 || xhr.status === 302 || xhr.status === 0) {
                // login page returned instead of json...
                // open a new window with relogon.html to trigger a new login
                window.showModalDialog("../relogon.html");
            } else {
                // normal error, pass along 
                if (originalError) {
                    originalError(model, xhr, options);
                }
            }
        }
    };

    // call the original sync
    Backbone.originalSync(method, model, options);
};

当从 0.9.9 升级到 1.0 时,这很糟糕。看起来原始的 Backbone.sync 以不同的方式包装其错误处理程序,导致我的错误处理程序首先被调用,并带有 jquery xhr 签名。我不得不将错误处理程序的签名更改为:

    options.error = function (xhr, statusTxt, thrown) {

好的,现在它可以工作了,但我觉得我做错了什么。

有一个更好的方法吗?

我尝试使用 jquery 承诺,但我需要能够从错误状态切换到成功(调用 originalSuccess 时),这似乎不适用于承诺。

4

2 回答 2

9

所有同步错误都会传递给模型的error事件,因此您可以收听此事件。

来自http://backbonejs.org/#Events-catalog

"error" (model, xhr, options) — 当模型的保存调用在服务器上失败时。

要全局捕获错误,您可以使用http://api.jquery.com/ajaxError/

于 2013-05-10T10:15:34.063 回答
8

您可以构建自己的 jQuery Deferred 对象来更改默认Backbone.sync行为

Backbone.sync = function (method, model, opts) {
    var xhr, dfd;

    dfd = $.Deferred();

    // opts.success and opts.error are resolved against the deferred object
    // instead of the jqXHR object
    if (opts)
        dfd.then(opts.success, opts.error);

    xhr = Backbone.originalSync(method, model, _.omit(opts, 'success', 'error'));

    // success : forward to the deferred
    xhr.done(dfd.resolve);

    // failure : resolve or reject the deferred according to your cases
    xhr.fail(function() {
        if (xhr.status === 200 && xhr.responseText === "") {
            dfd.resolve.apply(xhr, arguments);
        } else {
            if (xhr.status === 200 || xhr.status === 302 || xhr.status === 0) {
                console.log('login');
            }
            dfd.reject.apply(xhr, arguments);
        }
    });

    // return the promise to add callbacks if necessary
    return dfd.promise();
};

承诺反映了您选择的最终状态。

http://jsfiddle.net/AsMYQ/4/失败演示,http://jsfiddle.net/AsMYQ/5/成功。

如果我可以

  • 您可能不应该Backbone.sync与您的登录处理如此紧密地联系在一起。使用来自 Backbone 或jQuery.ajaxError@Andrey 建议的事件
  • 您的服务器响应应该指示授权失败,可能是 401 状态
  • 当您覆盖同步时,不要忘记返回您的延迟承诺/jqXHR 对象,这可能会派上用场
于 2013-05-10T19:56:24.493 回答