Ember.js 在路由转换时重新创建服务对象

Ember.js Service objects recreated on route transition

正如我从文档中了解到的那样,服务基本上是一个单例对象,用于在整个应用程序生命周期中为其他对象提供服务。我有一个用户管理服务,在用户使用路由 /users/login 登录后,我用它来保存身份验证令牌。但是转换到另一条路线(例如/composer)会导致重新创建服务实例,因此它会丢失所有存储的数据。这是否与它应该与应用程序一样存在的事实相矛盾,或者我对整个生命周期的想法有误吗?

我在我的所有路由中注入服务,如下所示:

authenticationService: Ember.inject.service('authentication-service'),

服务本身只是一组 getter 和 setter:

import Ember from 'ember';

export default Ember.Service.extend({
    currentUser: undefined,
    jwtToken: undefined,
    // ================================================================================================================ \
    // ================================================================================================================ \
    // ================================================================================================================ \
    setCurrentUser(user) {
        this.currentUser = user ;
    },
    getCurrentUser() {
        return this.currentUser ;
    },
    isLoggedIn() {
        return Boolean(this.currentUser) ;
    },
    getJwtToken() {
        return this.jwtToken ? this.jwtToken : '' ;
    },
    setJwtToken(jwtToken) {
        this.jwtToken = jwtToken ;
    }
});

登录令牌的处理方式如下:

actions: {
    onSubmitLoginForm() {
        if (!this.validateLoginForm()) {
            return ;
        }
        var self = this ;
        Ember.$.post('login/', {
            'username': this.controller.get('username'),
            'password': this.controller.get('password'),
            'email':    this.controller.get('email'),
        }, function(data) {
            console.log(data) ;
            if (data['success'] === 'Ok') {
                self.get('authenticationService').setJwtToken(data['auth']['jwt']) ;
                var user = self.get('store').createRecord('user', {
                    username: data['auth']['user']['username'],
                    email   : data['auth']['user']['email'],
                    mongoId : data['auth']['user']['id']['$oid'],
                }) ;
                self.get('authenticationService').setCurrentUser(user) ;
                self.transitionTo('home') ;
                console.log('logged in') ;
                console.log(self.get('authenticationService').getJwtToken()) ;
                console.log(self.get('authenticationService').getCurrentUser()) ;
                console.log(self.get('authenticationService').isLoggedIn()) ;
            } else {
                self.transitionTo('error') ;
            }
        }) ;
    },
}

我不是在寻找有关使用其他一些持久性方法(例如 IndexedDB)的建议;我愿意了解这件事实际上是如何工作的,因此不胜感激。

是的,您没看错 - 服务是单调的,我可以向您保证,服务在转换之间保持其状态。但是要进行转换,您必须使用 link-to 助手。如果您手动更改 url,您将重新加载您的应用程序而不是转换。应用程序重新加载当然会导致状态重置。您应该使用任何可用类型的存储来保存页面重新加载之间的状态。可能是本地存储、会话存储、cookie等

此外,在 Ember 中我们不使用这样的代码:this.currentUser = user ; 在 Ember 对象上。我们使用 this.set('currentUser', user); 代替。否则 Ember 将无法重新渲染模板、更新计算属性并正常工作。

最后,您不应该从零开始构建身份验证解决方案。这是一件非常困难和复杂的事情。相反,您可以使用 ember-simple-auth 插件并在其上构建身份验证过程。这会容易得多,结果也会更可靠。