2015年重新审视了Ember Handling 401s

时间:2015-04-28 17:57:58

标签: ruby-on-rails ember.js error-handling ember-data

我可以找到大量旧问题,询问/回答如何在Ember / Ember数据中处理来自Rails后端的401s。许多(如果不是全部)在这一点上似乎已经过时了。我已经尝试了所有可以找到的东西。 (Ember-Data handling 401’s

但无论我做什么,我都会在控制台中不断收到401错误,而我的代码中永远不会收到401错误。我想要做的就是添加重定向到' /'如果在任何地方/模型/任何地方遇到过401。我不需要检查身份验证或其他任何事情。

我尝试将此添加到Application Route操作以及路由器本身。

error: function (error, transition) {
  console.log("err: " + error.status);
  if (error && error.status === 401) {
    return this.transitionToRoute('/');
  }
}

我还试过了https://stackoverflow.com/a/19063009/1850353的几种变体。

App.ApplicationAdapter = DS.RESTAdapter.extend({
  ajaxError: function(jqXHR) {
    var error = this._super(jqXHR);
    console.log("jqXHR: " + jqXHR.status);
    if (jqXHR && jqXHR.status === 401) {
      #handle the 401 error
    }
    return error;
  }
});

我显然是个菜鸟,所以也许我在这里错过了一些简单的东西。我的console.log都没有被触发,除非它引发了一个新的错误,我试图让它运行起来。是否有最新的最佳做法'风格的做法?

3 个答案:

答案 0 :(得分:3)

这里的其他两个答案都很好,并且可以正常工作,但有一些不受欢迎的警告恕我直言。

我强烈建议实施Ember.onerror钩子。任何未经处理的承诺拒绝都会在那个钩子上结束。如果您使用的是Ember-CLI,则可以使用初始化程序实现它。

// app/initializers/on-error.js
export default {
  name: 'on-error',
  initialize: function(container, app) {
    Ember.onerror = function(error) {
      if(error && error.status === 401) {
        // Ember 2.1 adds a public lookup function. Older versions
        // need to use the container.
        var router = app.lookup ? app.lookup('router:main') :
                     app.__container__.lookup('router:main');
        // Even future versions of ember are likely to have an 
        // accessible router service to do this work.
        router.transitionTo('sign-in');
      }

      if(error && error.stack) {
        // Uncaught exception - Log stacktrace to server
      }
    };
  }
}

如上所述,这将处理所有未被捕获的承诺拒绝。因此,这仍然为您提供了在组件中本地处理承诺的灵活性。例如:

export default Ember.Component.extend({
  actions: {
    saveChanges: function() {
      this.get('model').save().then(null, (reason) => {
        if(/* reason is validation error */) {
          this.set('validationError', reason.errorMsg);
        } else {
          throw reason;
        }
      })
    }
  }
 });

请注意,如果我们无法处理错误,请在上面的promise拒绝处理程序中重新抛出它。这是非常重要的。重新抛出错误将使任何其他链式承诺处理程序有机会处理它。如果不加以处理,它最终将会达到Ember.onerror

答案 1 :(得分:2)

使用Ember 1.13.8& Ember Data 1.13.9,我的认证路线使用:

actions: {
  error: function(reason, transition) {
    if (reason.errors[0].status === '401') {
      this.transitionTo('sign-in');
    }
  }
}

答案 2 :(得分:1)

控制器和路由

使用在控制器或路由中执行的逻辑,您通常会在路径上附加error操作。如果在控制器上触发操作并且控制器未处理该操作(例如,控制器error哈希中没有actions操作)则会自动将其传递给路径以获取机会处理 - 如果当前路由没有处理该操作,它将起泡到父路由,直到它到达ApplicationRoute

我处理它的方式是AuthenticatedRoute,任何需要处理401的路径都来自。此外,在您链接的示例中 - 它有events,而现在是actions

这样的事情对你有用:

    App.AuthenticatedRoute = Ember.Route.extend({

        actions: {
        error: function(error) {
            if (!error || error.status !== 401) {
                // returning true bubbles the error to parent routes
                return true; 
            }

                // put your logic here
                console.log('this is a 401 error.');
            }
        }

    });

    App.IndexRoute = App.AuthenticatedRoute.extend({
        //logic
    });

    App.FooRoute = App.AuthenticatedRoute.extend({
        //logic
    });

    App.BarRoute = App.AuthenticatedRoute.extend({
        //logic
    });

部件

Ember正在越来越多地转向组件 - 在组件中执行逻辑的事情是它与其他所有东西完全隔离。通常,组件中可用的唯一内容就是您传递给它们的内容。

这意味着,如果您在组件中执行某些逻辑,则不使用上述逻辑 - 处理错误的路由上存在的逻辑 - 除非您自己明确使用它。

如果您在组件中调用store.find('person', 1)person.save(),则需要使用.catch()函数明确处理错误或将第二个函数传递给.then()。例如,以下两个语句将执行相同的操作:

    store.find('person', 1).then(function(person) {
        console.log('found person 1:', person);
    }, function(err) {
        console.log('error finding person 1:', err);
    });

    store.find('person', 1).then(function(person) {
        console.log('found person 1:', person);
    }).catch(function(err) {
        console.log('error finding person 1:', err);
    });

这两个陈述也是如此:

    person.save().then(function() {
        console.log('successfully saved person');
    }, function(err) {
        console.log('error saving person:', err);
    });

    person.save().then(function() {
        console.log('successfully saved person');
    }).catch(function(err) {
        console.log('error saving person:', err);
    });

重用组件中的路径错误逻辑

如果要将组件中的错误处理传递到路由上以处理最佳方法,请让组件触发操作并让调用模板/视图/控制器处理它。

app/components/my-component.js

    Ember.Component.extend({
        'on-error': null,
        model: null,
        actions: {
            save: function() {
                var component = this;
                var model = this.get('model');

                mode.save().then(function() {
                    console.log('saved');
                }).catch(function(err) {
                    component.sendAction('on-error', err);
                });
            }
        }
    });

app/templates/components/my-component.hbs

    <button {{action 'save'}}>Save</button>

app/templates/index.hbs

    <!-- 
        Passing the 'error' action to the components 'on-error' property links the 'on-error' 
        action on the component with the 'error' action on the controller - if the controller 
        doesn't handle it, it's bubbled up to the route to handle
    -->

    {{my-component model=model on-error='error'}}