我需要在服务器的所有响应中捕获可能的登录页面,因此我全局覆盖了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,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,options); } } } }; // call the original sync Backbone.originalSync(method,options); };
当从0.9.9变为1.0时,这种情况很糟糕.看起来原始的Backbone.sync以不同的方式包装其错误处理程序,导致我的错误处理程序首先被调用,带有jquery xhr签名.
我不得不将错误处理程序的签名更改为:
options.error = function (xhr,statusTxt,thrown) {
好吧现在它有效,但我觉得我做错了.
有一个更好的方法吗?
我尝试使用jquery promises,但我需要能够从错误状态切换到成功(当调用originalSuccess时),这似乎不适用于promises.
解决方法
您可以构建自己的jQuery
Deferred object来更改默认的Backbone.sync行为
Backbone.sync = function (method,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,_.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状态>当您覆盖同步时,不要忘记返回延迟的promise / jqXHR对象,这可能会派上用场