0

有没有办法普遍拦截 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 响应代码(即内存中的用户实体/表示)之外的其他内容,它也不能正常工作。

4

2 回答 2

1

Marionette.AppRouter extends the standard Backbone.Router, neither of them provides an interception mechanism that allow you to prevent the execution of a route callback. In need of the same features, I came up with the following code (_ is Lodash). In the original Backbone.Router.prototype.route(), a function that will be executed on a route match is created. The following code provides a wrapper for the original Backbone.Router.prototype.route() in order to replace the registered route callback with a function that will execute a chain of middleware functions. Each of these middleware can then perform any additional processing before or after execution of the original route callback, including preventing execution of further callback and raise exception.

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);

Using this interceptors/middlewares mechanism, redirection of the user to the login page could be achieved with the following:

Backbone.RouteMiddlewares.use(function (route, name, fragment, args, next) {
  if (App.routeRequiresAuthentication(name) && !App.isUserAuthenticated()) {
    Backbone.history.navigate('login', {trigger: true});
  }
  else {
    next();
  }
});

Note: Being able to execute code after the route callback via middlewares is redundant with the route events on the router and on Backbone.history but it comes free with the middleware pattern.

于 2015-04-13T20:06:24.913 回答
0

您可以使用 Backbone.sync。此同步是 Backbone 在每次获取、保存操作时调用的函数。默认情况下,它使用 jquery ajax 进行调用。您可以覆盖 Backbone.sync 函数中的 ajax 调用,以便控制服务器交互。这是Backbone.Sync 文档

于 2013-07-15T13:48:56.817 回答