Javascript AngularJS ui路由器$stateChangeStart带有限循环

Javascript AngularJS ui路由器$stateChangeStart带有限循环,javascript,angularjs,angular-ui-router,Javascript,Angularjs,Angular Ui Router,我正在尝试在angular应用程序中构建某种身份验证,并希望在用户未登录时重定向到外部URL(基于$http.get) 不知何故,当event.preventDefault()是$stateChangeStart中的第一行时,我最终进入了一个无限循环 我在stackoverflow上看到过多个问题的答案,比如“将event.preventDefault()放在state.go前面的else中”。但随后控制器被触发,页面在承诺返回之前已经显示 即使我将event.preventDefault()放

我正在尝试在angular应用程序中构建某种身份验证,并希望在用户未登录时重定向到外部URL(基于$http.get)

不知何故,当event.preventDefault()是$stateChangeStart中的第一行时,我最终进入了一个无限循环

我在stackoverflow上看到过多个问题的答案,比如“将event.preventDefault()放在state.go前面的else中”。但随后控制器被触发,页面在承诺返回之前已经显示

即使我将event.preventDefault()放在else中,也会发生一些奇怪的事情:

转到根URL,它会在多次激发URL和$stateChangeStart之后自动添加/#/

app.js运行部分:

.run(['$rootScope', '$window', '$state', 'authentication', function ($rootScope, $window, $state, authentication) {
    $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
        event.preventDefault();
        authentication.identity()
        .then(function (identity) {
             if (!authentication.isAuthenticated()) {
                 $window.location.href = 'external URL';
                 return;
            } else {
                 $state.go(toState, toParams);
            }
        });
    });
}]);
authentication.factory.js identity()函数:

function getIdentity() {
    if (_identity) {
        _authenticated = true;
        deferred.resolve(_identity);
        return deferred.promise;
    }

    return $http.get('URL')
    .then(function (identity) { 
        _authenticated = true;
        _identity = identity;
        return _identity;
    }, function () {
        _authenticated = false;
    });
}
编辑:添加状态:

$stateProvider
    .state('site', {
        url: '',
        abstract: true,
        views: {
            'feeds': {
                templateUrl: 'partials/feeds.html',
                controller: 'userFeedsController as userFeedsCtrl'
            }
        },
        resolve: ['$window', 'authentication', function ($window, authentication) {
            authentication.identity()
            .then(function (identity) {
                if (!authentication.isAuthenticated()) {
                    $window.location.href = 'external URL';
                }
            })
        }]
    })
    .state('site.start', {
        url: '/',
        views: {
            'container@': {
                templateUrl: 'partials/start.html'
            }
        }
    })
    .state('site.itemList', {
        url: '/feed/{feedId}',
        views: {
            'container@': {
                templateUrl: 'partials/item-list.html',
                controller: 'itemListController as itemListCtrl'
            }
        }
    })
    .state('site.itemDetails', {
        url: '/items/{itemId}',
        views: {
            'container@': {
                templateUrl: 'partials/item-details.html',
                controller: 'itemsController as itemsCtrl'
            }
        }
    })
}])

如果您需要更多的信息,或者app.js中的更多代码,请告诉我

$stateChangeStart
在退出之前不会等待您的承诺得到解决。使状态等待承诺的唯一方法是在状态选项中使用
resolve

.config(function($stateProvider) {
  $stateProvider.state('home', {
    url: '/',
    resolve: {
      auth: function($window, authentication) {
        return authentication.identity().then(function (identity) {
           if (!authentication.isAuthenticated()) {
             $window.location.href = 'external URL';
           }
        });
      }
    }
  });
});
通过从函数返回承诺,ui路由器将不会初始化状态,直到该承诺得到解决

如果您有其他或子状态需要等待,则需要在中插入
auth

从:

如果要在实例化子级之前等待承诺被解析,则必须将解析键注入子级状态


您已经尝试添加以下行:$locationProvider.html5Mode(true);在您的路由配置中。并将此元数据添加到html标头:。这将删除URL末尾的丑陋/#。哦,是的,我忘记了html5mode()记录,谢谢!实际上我两者都有。因为解析只触发一次(第一次加载页面时)。或者是否有办法确保始终触发解析?是的,您可以使用
$state.go()
重新加载
选项。但是如果您有其他解析,那么这将是低效的,因为它们也将被重新加载。既然您正在缓存
\u标识
,为什么每次都要触发它?我在问题中添加了我的状态。我不希望每次都触发解析,我希望在加载任何状态之前进行某种身份验证检查。这就是为什么我使用stateChangeStart,它在每次状态更改时都会启动。调试时,我可以看到当承诺返回时,state.go将被激发,因此您确定stateChangeStart不会等待承诺吗?是的,
then
块中的代码将被执行。我的意思是,无论承诺的状态如何,状态改变都将继续,这就是为什么你看到你的控制器在承诺解决之前开火。