javascript AngularJS : angular-ui-router 总是重定向到 $urlRouterProvider.otherwise 位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31896150/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 14:32:22  来源:igfitidea点击:

AngularJS : angular-ui-router always redirects to $urlRouterProvider.otherwise location

javascriptangularjsangular-ui-router

提问by Brent Parker

I'm trying to create an SPA where you have to be logged in to access almost everything. So naturally, the default screen you see is the login screen. However, after a user has logged in, no matter what the ui-sref is, ui-router redirects to the login page (even when the user is authenticated). Here is my ui-router code:

我正在尝试创建一个 SPA,您必须登录才能访问几乎所有内容。很自然,您看到的默认屏幕是登录屏幕。但是,在用户登录后,无论 ui-sref 是什么,ui-router 都会重定向到登录页面(即使用户已通过身份验证)。这是我的 ui-router 代码:

(function () {
'use strict';
angular
    .module('app', ['ui.router', 'satellizer'])
    .config(function ($stateProvider, $urlRouterProvider, $authProvider, $httpProvider, $provide) {
  
        $httpProvider.interceptors.push(['$q', '$injector', function($q, $injector){
            return {
                responseError: function (rejection) {
                    var $state = $injector.get('$state');
                    var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
                    angular.forEach(rejectionReasons, function (value, key) {
                        if (rejection.data.error === value) {
                            localStorage.removeItem('user');
                            $state.go('auth');
                        }
                    });

                    return $q.reject(rejection);
                },
                response: function(response) {
                    var authorization = response.headers('authorization');
                    if(authorization !== null) {
                        authorization = authorization.substr(7).trim();
                        //console.log(authorization);
                        var $auth = $injector.get('$auth');
                        $auth.setToken(authorization);
                    }
                    return response;
                }
            }
        }]);

        $authProvider.loginUrl = 'mingdaograder/api/authenticate';

        $stateProvider
            .state('users', {
                url: '/users',
                templateUrl: 'views/userView.html',
                controller: 'UserController as user'
            })
            .state('subjects', {
                url: '/users/:user_id/subjects',
                templateUrl: 'views/subjectsView.html',
                controller: 'SubjectsCtrl as subjectsCtrl'
            })
            .state('subject', {
                url: '/users/:user_id/subjects/:subject_id',
                templateUrl: 'views/subjectView.html',
                controller: 'SubjectCtrl as subjectCtrl'
            })
            .state('auth', {
                url: '/auth',
                templateUrl: 'views/authView.html',
                controller: 'AuthController as auth'
            });
            //.state('otherwise', {
            //    url: '*path',
            //    templateUrl: 'views/authView.html',
            //    controller: 'AuthController as auth'
            //});

            //$urlRouterProvider.otherwise('/auth');
            $urlRouterProvider.otherwise(function($injector, $location) {
                console.log("Could not find " + $location);
                $location.path('/auth');
            });
    })
    .run(function ($rootScope, $state, $log) {
        $rootScope.$on('$stateChangeStart', function (event, toState) {
                console.log(toState.name);
            var user = JSON.parse(localStorage.getItem('user'));
            if (user) {
                $rootScope.authenticated = true;
                $rootScope.currentUser = user;
            }
        }
        );
    }
);
})();

Anytime I try to use $state.go(any state name here) or even type the address into the address bar, I am always redirected to the auth state. On the console the message is "Could not find http://localhost/#/" for every single route. I can type in http://localhost/#/users/5/subjectsand I get the same message.

每当我尝试使用 $state.go(此处的任何州名)甚至在地址栏中键入地址时,我总是被重定向到身份验证状态。在控制台上,每条路由的消息都是“找不到http://localhost/#/”。我可以输入http://localhost/#/users/5/subjects并得到相同的消息。

Here is one of my controllers doing a redirect:

这是我的一个控制器进行重定向:

(function () {
    'use strict';

    angular
        .module('app')
        .controller('AuthController', AuthController);

    function AuthController($auth, $state, $http, $rootScope, $log) {
        var vm = this;

        vm.loginError = false;
        vm.loginErrorText;

        vm.login = function () {
            var credentials = {
                username: vm.username,
                password: vm.password
            };

            $auth.login(credentials).then(function () {
                return $http.get('api/authenticate/user');
            }, function (error) {
                vm.loginError = true;
                vm.loginErrorText = error.data.error;
            }).then(function (response) {
                var user = JSON.stringify(response.data.user);
                localStorage.setItem('user', user);
                $rootScope.authenticated = true;
                $rootScope.currentUser = response.data.user;

                //$log.info('From AuthCtrl: ' + $rootScope.currentUser.id);
                $state.go('subjects', {user_id:$rootScope.currentUser.id});
            });
        }
    }
})();

Any ideas what I'm doing wrong? Thanks a lot for your time.

任何想法我做错了什么?非常感谢您的时间。

Update: Ok, I haven't found a way to fix it but I think I may have found a possible cause. It seems to only happen for the routes with parameters. For example, if I go to the usersstate, whose path is /users, there is no redirect. However, if I go to the subjectsstate, whose path is /users/:user_id/subjects, it does redirect. It's like the Url matching service can't recognize that /users/5/subjects matches /users/:user_id/subjects, so redirects. Any ideas how to work around this?

更新:好的,我还没有找到修复它的方法,但我想我可能已经找到了可能的原因。它似乎只发生在带有参数的路由上。例如,如果我转到路径为 /users的用户状态,则没有重定向。但是,如果我去科目状态,其路径为/用户/:USER_ID /科目,它重定向。这就像 Url 匹配服务无法识别 /users/5/subjects 匹配 /users/:user_id/subjects,因此重定向。任何想法如何解决这个问题?

回答by sarin

I found I didn't have a '/' at the beginning of my initial state url. Every time I navigated to the state, the missing '/' seemed to push it into the stateProvider.otherwise.

我发现我的初始状态 url 的开头没有“/”。每次我导航到状态时,缺少的“/”似乎将它推入 stateProvider.otherwise。

state1: 'opportunity'
state1Url : '/opportunity/' <== added initial forward slash to make it work.

state2: 'opportunity.create'
state2Url : 'create/'

回答by biofractal

The first path to be recognised will be the selected as the current location. This means that the order of your route definitions is crucially important. In your case you only have a single catch-all otherwiseroute definition and since all routes match this then all routes are directed to your login page ignoring any other route definitions you may have, including all your stateProviderstate definitions.

要识别的第一条路径将被选为当前位置。这意味着路由定义的顺序至关重要。在您的情况下,您只有一个包罗万象的otherwise路由定义,并且由于所有路由都与此匹配,因此所有路由都被定向到您的登录页面,而忽略您可能拥有的任何其他路由定义,包括所有stateProvider状态定义。

One way to fix this is to remove the urlRouterProviderroute definition altogether and instead use the *pathsyntax provided by ui-routerto create an alternative otherwisestate (which must be defined last for the same reasons given above).

解决此问题的一种方法是完全删除urlRouterProvider路由定义,而是使用*path提供的语法ui-router来创建替代otherwise状态(出于与上述相同的原因,必须最后定义)。

Therefore your code might look something like this:

因此,您的代码可能如下所示:

$stateProvider
    .state('auth', {
        url: '/auth',
        templateUrl: 'views/authView.html',
        controller: 'AuthController as auth'
    })
    .state('users', {
        url: '/users',
        templateUrl: 'views/userView.html',
        controller: 'UserController as user'
    })
    .state('subjects', {
        url: '/users/:user_id/subjects',
        templateUrl: 'views/subjectsView.html',
        controller: 'SubjectsCtrl as subjectsCtrl'
    })
    .state('subject', {
        url: '/users/:user_id/subjects/:subject_id',
        templateUrl: 'views/subjectView.html',
        controller: 'SubjectCtrl as subjectCtrl'
    })
    .state("otherwise", {
        url: "*path",
        templateUrl: 'views/authView.html',
        controller: 'AuthController as auth'
    });

回答by u6123141

(function () {
'use strict';
angular
    .module('app', ['ui.router', 'satellizer'])
    .config(function ($stateProvider, $urlRouterProvider, $authProvider, $httpProvider, $provide) {
  
        $httpProvider.interceptors.push(['$q', '$injector', function($q, $injector){
            return {
                responseError: function (rejection) {
                    var $state = $injector.get('$state');
                    var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];
                    angular.forEach(rejectionReasons, function (value, key) {
                        if (rejection.data.error === value) {
                            localStorage.removeItem('user');
                            $state.go('auth');
                        }
                    });

                    return $q.reject(rejection);
                },
                response: function(response) {
                    var authorization = response.headers('authorization');
                    if(authorization !== null) {
                        authorization = authorization.substr(7).trim();
                        //console.log(authorization);
                        var $auth = $injector.get('$auth');
                        $auth.setToken(authorization);
                    }
                    return response;
                }
            }
        }]);

        $authProvider.loginUrl = 'mingdaograder/api/authenticate';

        $stateProvider
            .state('users', {
                url: '/users',
                templateUrl: 'views/userView.html',
                controller: 'UserController as user'
            })
            .state('subjects', {
                url: '/users/:user_id/subjects',
                templateUrl: 'views/subjectsView.html',
                controller: 'SubjectsCtrl as subjectsCtrl'
            })
            .state('subject', {
                url: '/users/:user_id/subjects/:subject_id',
                templateUrl: 'views/subjectView.html',
                controller: 'SubjectCtrl as subjectCtrl'
            })
            .state('auth', {
                url: '/auth',
                templateUrl: 'views/authView.html',
                controller: 'AuthController as auth'
            });
            //.state('otherwise', {
            //    url: '*path',
            //    templateUrl: 'views/authView.html',
            //    controller: 'AuthController as auth'
            //});

            //$urlRouterProvider.otherwise('/auth');
            $urlRouterProvider.otherwise(function($injector, $location) {
                console.log("Could not find " + $location);
                $location.path('/auth');
            });
    })
    .run(function ($rootScope, $state, $log) {
        $rootScope.$on('$stateChangeStart', function (event, toState) {
                console.log(toState.name);
            var user = JSON.parse(localStorage.getItem('user'));
            if (user) {
                $rootScope.authenticated = true;
                $rootScope.currentUser = user;
            }
        }
        );
    }
);
})();