Ember 2015 年重新处理 401
Ember Handling 401s Revisited in 2015
我可以在 Ember/Ember 数据中找到大量老问题 asking/answering 如何处理来自 Rails 后端的 401。许多,如果不是全部,在这一点上似乎已经过时了。我已经尝试了我能找到的一切。 (Ember-Data handling 401’s)
但无论我做什么,我总是在控制台中收到 401 错误,而 401 错误从未出现在我的代码中。如果在任何 place/model/anything 中遇到 401,我想要做的就是将重定向添加到“/”。我不需要任何身份验证检查或其他任何检查。
我已经尝试将其添加到应用程序路由操作以及路由器本身。
error: function (error, transition) {
console.log("err: " + error.status);
if (error && error.status === 401) {
return this.transitionToRoute('/');
}
}
我也试过这个的几种变体。
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 中的 None 被触发了,除非它是我引入的新错误,试图让它工作。是否有当前的 'best practice' 风格的方式来做到这一点?
控制器和路由
对于在控制器或路由中执行的逻辑,您通常会在路由上附加一个 error
操作。如果在控制器上触发了一个动作并且控制器没有处理那个动作(例如控制器 actions
哈希中没有 error
动作)那么它会自动传递给路由以获得机会处理 - 如果当前路由不处理操作,它会冒泡到父路由,直到它到达 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 正在越来越多地转向组件 - 在组件中执行逻辑的事情是它与其他一切完全隔离。通常,您在组件中唯一可用的是您传递给它们的东西。
这意味着如果您在上述逻辑的组件 none 中执行某些逻辑 - 路由中存在的用于处理错误的逻辑 - 将被使用,除非您自己明确使用它。
如果您在组件中进行 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);
});
在组件中重用路由错误逻辑
如果您想将组件中的错误处理传递给路由以进行处理,最好的方法是让组件触发一个操作并让调用 template/view/controller 处理它。
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'}}
使用 Ember 1.13.8 & Ember 数据 1.13.9,我的认证路由使用:
actions: {
error: function(reason, transition) {
if (reason.errors[0].status === '401') {
this.transitionTo('sign-in');
}
}
}
这里的其他两个答案都很好,可以正常工作,但恕我直言,有一些不受欢迎的警告。
我强烈建议实施 Ember.onerror
挂钩。任何未处理的 promise 拒绝都将在那个钩子上结束。如果您使用 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
}
};
}
}
如上所述,这将处理所有未捕获的承诺拒绝。因此,这仍然为您提供了很大的灵活性,可以在组件中本地处理 promises。例如:
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;
}
})
}
}
});
请注意,在上面的承诺拒绝处理程序中,如果我们无法处理错误,我们将重新抛出它。这个非常重要。重新抛出错误将为任何其他链式承诺处理程序提供处理它的机会。如果不加以处理,最终它将达到 Ember.onerror
。
我可以在 Ember/Ember 数据中找到大量老问题 asking/answering 如何处理来自 Rails 后端的 401。许多,如果不是全部,在这一点上似乎已经过时了。我已经尝试了我能找到的一切。 (Ember-Data handling 401’s)
但无论我做什么,我总是在控制台中收到 401 错误,而 401 错误从未出现在我的代码中。如果在任何 place/model/anything 中遇到 401,我想要做的就是将重定向添加到“/”。我不需要任何身份验证检查或其他任何检查。
我已经尝试将其添加到应用程序路由操作以及路由器本身。
error: function (error, transition) {
console.log("err: " + error.status);
if (error && error.status === 401) {
return this.transitionToRoute('/');
}
}
我也试过这个的几种变体。
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 中的 None 被触发了,除非它是我引入的新错误,试图让它工作。是否有当前的 'best practice' 风格的方式来做到这一点?
控制器和路由
对于在控制器或路由中执行的逻辑,您通常会在路由上附加一个 error
操作。如果在控制器上触发了一个动作并且控制器没有处理那个动作(例如控制器 actions
哈希中没有 error
动作)那么它会自动传递给路由以获得机会处理 - 如果当前路由不处理操作,它会冒泡到父路由,直到它到达 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 正在越来越多地转向组件 - 在组件中执行逻辑的事情是它与其他一切完全隔离。通常,您在组件中唯一可用的是您传递给它们的东西。
这意味着如果您在上述逻辑的组件 none 中执行某些逻辑 - 路由中存在的用于处理错误的逻辑 - 将被使用,除非您自己明确使用它。
如果您在组件中进行 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);
});
在组件中重用路由错误逻辑
如果您想将组件中的错误处理传递给路由以进行处理,最好的方法是让组件触发一个操作并让调用 template/view/controller 处理它。
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'}}
使用 Ember 1.13.8 & Ember 数据 1.13.9,我的认证路由使用:
actions: {
error: function(reason, transition) {
if (reason.errors[0].status === '401') {
this.transitionTo('sign-in');
}
}
}
这里的其他两个答案都很好,可以正常工作,但恕我直言,有一些不受欢迎的警告。
我强烈建议实施 Ember.onerror
挂钩。任何未处理的 promise 拒绝都将在那个钩子上结束。如果您使用 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
}
};
}
}
如上所述,这将处理所有未捕获的承诺拒绝。因此,这仍然为您提供了很大的灵活性,可以在组件中本地处理 promises。例如:
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;
}
})
}
}
});
请注意,在上面的承诺拒绝处理程序中,如果我们无法处理错误,我们将重新抛出它。这个非常重要。重新抛出错误将为任何其他链式承诺处理程序提供处理它的机会。如果不加以处理,最终它将达到 Ember.onerror
。