有没有办法一般拦截MarionetteJS操作,例如路由和模型提取?
并行将是AngularJS中的$ httpInterceptor(https://stackoverflow.com/a/11957760/41887)
我感兴趣的用例是用户身份验证,如果没有当前用户身份验证,则重定向到登录页面/路由。虽然我可以在每个控制器中专门处理这个问题,但我更倾向于使用一个全局应用的通用机制。
更新
为了获取拦截,我看到一个建议如下:
AuthenticationModule.addInitializer ->
# Tell jQuery to watch for any 401 or 403 errors and handle them appropriately
$.ajaxSetup {
statusCode: {
401: -> window.location.replace('#login')
403: -> window.location.replace('#denied')
}
}
但如果您想要对HTTP响应代码(即内存中的用户实体/表示)之外的内容进行验证,它也不会起作用。
答案 0 :(得分:1)
Marionette.AppRouter
扩展了标准Backbone.Router
,它们都没有提供允许您阻止执行路由回调的拦截机制。需要相同的功能,我想出了以下代码(_
是Lodash)。在原始Backbone.Router.prototype.route()
中,将创建将在路由匹配上执行的函数。以下代码为原始Backbone.Router.prototype.route()
提供了一个包装器,以便使用将执行一系列中间件函数的函数替换已注册的路由回调。然后,每个中间件都可以在执行原始路由回调之前或之后执行任何其他处理,包括阻止执行进一步的回调并引发异常。
Backbone.RouteMiddlewares = (function () {
var Backbone = require('backbone')
, _ = require('lodash');
/**
* A wrapper for `Backbone.Router.prototype.route()` that will use route middlewares (in addition to its
* normal callback).
*
* @param {Function} fn - The wrapped function (should be compatible with `Backbone.Router.prototype.route()`).
* @param {string|RegExp} route - A route pattern or regexp.
* @param {string} name - The name of the route.
* @param {Function} callback - The route callback.
* @returns {Backbone.Router}
*/
function RouteMiddleware(fn, route, name, callback) {
// Prepare arguments as the original Backbone.Router.prototype.route() would.
if (!_.isRegExp(route)) route = Backbone.Router.prototype._routeToRegExp.apply(this, [route]);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
// Execute the wrapper `route` method, with the callback as final middleware.
return fn.apply(this, [route, name, function () {
executeMiddlewares.apply(this, [route, name, Backbone.history.getFragment(), Array.prototype.slice.apply(arguments, [0]), callback]);
}]);
};
/**
* Add a route middelware.
*
* @param {RouteMiddleware} fn
*/
RouteMiddleware.use = function use(fn) {
middlewares.push.apply(middlewares, _.filter(arguments, _.isFunction));
};
/**
* @callback RouteMiddleware
* @param {RegExp} route - The matched route regexp.
* @param {string} name - The matched route.
* @param {string} fragment - The matched URL fragment.
* @param {Array} args - The route arguments (extracted from `fragment`).
* @param {Function} next - The function to call to execute the next middleware in the chain.
*/
/**
* @type {RouteMiddleware[]}
*/
var middlewares = [];
/**
* Execute the route middlware, ending with the provided callback.
*
* @param {RegExp} route - The matched route regexp.
* @param {string} name - The matched route.
* @param {string} fragment - The matched URL fragment.
* @param {Array} args - The route arguments (extracted from `fragment`).
* @param {Function} callback - The route handler to execute as final middleware.
*/
function executeMiddlewares(route, name, fragment, args, callback) {
var index = 0;
var h = middlewares.concat(function (route, name, fragment, args, next) {
callback.apply(this, args);
});
function next(err) {
if (err) throw err;
h[index++].apply(this, [route, name, fragment, args, next.bind(this)]);
}
next.apply(this);
}
})();
Backbone.Router.prototype.route = _.wrap(Backbone.Router.prototype.route, Backbone.RouteMiddlewares);
使用此拦截器/中间件机制,可以通过以下方式将用户重定向到登录页面:
Backbone.RouteMiddlewares.use(function (route, name, fragment, args, next) {
if (App.routeRequiresAuthentication(name) && !App.isUserAuthenticated()) {
Backbone.history.navigate('login', {trigger: true});
}
else {
next();
}
});
注意:能够在通过中间件进行路由回调之后执行代码对于路由器和route
上的Backbone.history
事件是多余的,但它随中间件模式免费提供。
答案 1 :(得分:0)
您可以使用Backbone.sync。此同步是Backbone调用每次提取,保存操作的功能。默认情况下,它使用jquery ajax进行调用。您可以覆盖Backbone.sync函数中的ajax调用,以便您可以控制服务器交互。这是Backbone.Sync documentation