Javascript $location.path不会加载相关页,如果其承诺在身份验证拦截期间被拒绝

Javascript $location.path不会加载相关页,如果其承诺在身份验证拦截期间被拒绝,javascript,angularjs,ajax,Javascript,Angularjs,Ajax,我在AngularJS应用程序中进行身份验证拦截时遇到问题 为了说明这一点,我制作了一个非常简化的应用程序版本,其中包含一个登录页面(路径/login)和一个Hello World页面(路径//code>),您必须登录才能看到。在路由提供者解析期间,Hello World页面上显示的问候语是通过Ajax获取的,只有提供了有效的访问令牌,此操作才会成功 这就是我的经历: 用户尝试访问位于/的Hello World页面 在可以加载Hello World页面控制器之前,应该从服务器获取问候语文本–因为

我在AngularJS应用程序中进行身份验证拦截时遇到问题

为了说明这一点,我制作了一个非常简化的应用程序版本,其中包含一个登录页面(路径
/login
)和一个Hello World页面(路径
//code>),您必须登录才能看到。在路由提供者解析期间,Hello World页面上显示的问候语是通过Ajax获取的,只有提供了有效的访问令牌,此操作才会成功

这就是我的经历:

  • 用户尝试访问位于
    /
    的Hello World页面
  • 在可以加载Hello World页面控制器之前,应该从服务器获取问候语文本–因为还不知道访问令牌,服务器会以
    状态401
    进行响应。这在身份验证拦截器的
    responseError
    中被捕获,用户从该拦截器重定向到位于
    /login
    的登录页面
  • 在登录页面,系统将提示用户输入凭据,直到服务器上的auth API满意并返回有效的访问令牌为止–此访问令牌将存储以供以后使用,用户将重定向到位于
    /
    的Hello World页面
  • 登录页面保持可见,而不是使用新获得的访问令牌重新蚀刻问候语文本,然后显示Hello World页面–地址栏中的URL更新为提及
    /
    ,而不是
    /login

    为什么与
    /
    相关的页面未加载?该承诺先前已被拒绝,但是否应不再尝试解决该承诺?
    或者我在这里尝试的方式是无法将promise内容与auth拦截混合使用?

  • 控制台屏幕截图:


    档案:

    index.html

    
    试验
    

    auth.html

    请登录
    用户名:
    密码:
    提交
    {{message}}

    auth.js

    var auth=angular.module(“Test.auth”,[“ngRoute”]);
    auth.factory(“AuthInterceptor”,函数($q,$location,UserInfo){
    返回{
    请求:函数(配置){
    if(config.url.indexOf(“/api/”)==0){
    config.headers[“AJAX”]=true;//=>这样服务器就不会在响应中包含WWW身份验证头,并且可以避免浏览器身份验证弹出窗口
    如果(!config.headers.Authorization)config.headers[“ACCESS-TOKEN”]=UserInfo.accessToken();
    }
    返回配置;
    },
    responseError:函数(响应){
    如果($location.path()!=“/login”){
    log(“responseError-401请求失败,转到/login”);
    UserInfo.forget();
    $location.path(“/login”);
    }
    返回$q.reject(响应);
    }
    };
    }).config(函数($httpProvider){
    $httpProvider.interceptors.push('AuthInterceptor');
    });
    auth.service(“auth”,函数($rootScope,$location,$http,UserInfo){
    this.logIn=函数(凭据){
    $http.get(“/api/v1/auth/login”{
    标题:{
    授权:“基本”+btoa(凭证.用户名+:“+凭证.密码)
    }
    })
    .成功(职能(负责人){
    UserInfo.create(主体);
    log(“登录-转到/”;
    $location.path(“/”);
    })
    .错误(函数(){
    $rootScope.$broadcast(“登录失败”);
    });
    };
    });
    身份验证服务(“UserInfo”,函数($window){
    this.init=函数(){
    如果(!$window.sessionStorage[“userInfo”])这个.forget();
    else this.userInfo=JSON.parse($window.sessionStorage[“userInfo”]);
    };
    this.create=函数(主体){
    this.userInfo={
    用户名:principal.userName,
    accessToken:principal.accessToken
    };
    $window.sessionStorage[“userInfo”]=JSON.stringify(this.userInfo);
    };
    this.forget=函数(){
    this.userInfo=null;
    $window.sessionStorage[“userInfo”]=null;
    };
    this.accessToken=函数(){
    返回this.userInfo==null?null:this.userInfo.accessToken;
    };
    });
    auth.controller(“AuthCtrl”,函数($scope,auth){
    $scope.logIn=Auth.logIn;
    $scope.$on(“登录失败”,函数(){
    $scope.message=“请提供有效凭据。”;
    });
    });
    

    hello.html

    {{hello}
    

    hello.js

    var hello=angular.module(“HelloApp”、“ngRoute”、“Test.auth”);
    hello.run(函数(UserInfo){
    UserInfo.init();
    });
    hello.config(函数($routeProvider){
    $routeProvider
    .when(“/login”{
    templateUrl:“/test/auth.html”,
    控制器:“AuthCtrl”
    })
    .当(“/”时{
    templateUrl:“/test/hello.html”,
    控制器:“HelloCtrl”,
    决心:{
    hello:函数(hello){
    log(“resolve.hello”);
    回复你好。承诺;
    }
    }
    })
    .否则({
    重定向至:“/”
    });
    });
    hello.service(“hello”,函数($http){
    this.promise=$http.get(“/api/v1/utils/hello”)
    .然后(功能(响应){
    console.log(“获取的”“+response.data+”);
    返回响应数据;
    });
    });
    hello.controller(“HelloCtrl”,函数($scope,hello){
    $scope.hello=hello;
    });
    
    这就是我认为正在发生的事情!以下代码:

    if ($location.path() !== "/login") {
     console.log("responseError - request failed with 401, go to /login");
     UserInfo.forget();
     $location.path("/login");
    }
    return $q.reject(response);
    
    $location.path()
    等于
    “\”


    如果位置路径为
    “\”

    则需要解决承诺问题。是的,问题是
    承诺只能评估一次,这是通过设计实现的。显而易见的解决方法是将
    promise
    属性更改为每次调用时都会返回新的
    promise
    的函数。因此,您可以执行以下操作:

    hello.service(“hello”,函数($http){
    this.promiseBuilder=函数(){
    返回$http.post(“/api/v1/utils/hello”)
    .然后(功能(响应){
    
        $routeProvider
            .when("/", {
                templateUrl: "/test/hello.html",
                controller: "HelloCtrl",
                resolve: {
                    hello: function (Hello) {
                        console.log("resolve.hello");
                        return Hello.promiseBuilder();
                    }
                }
            })