身份验证-$http'调用了s.then()成功回调,而不是错误回调

Authentication - $http's .then() success callback called instead of error callback

本文关键字:回调 成功 错误 then http 调用 身份验证      更新时间:2023-09-26

这可能只是因为我对如何在MEAN堆栈应用程序中最好地进行身份验证存在误解,或者我对promise和$http的.then()方法的工作原理缺乏了解,但每当我试图使用不正确的凭据向后端Node服务器进行身份验证时,它都会调用$http的.then()方法的成功回调,而不是错误回调。这是我的设置:

我使用jsonwebtokenexpress-jwt包,AngularJS拦截器添加令牌以请求和检查状态401 responseErrors,设置/删除等JWT的TokenService,以及处理登录、注销等的UserService。

从调试开始,发生了以下情况:

  1. 发出登录请求
  2. 服务器捕获请求,查找指定的用户,但在数据库中找不到他们。返回401错误,JSON对象包括错误消息等
  3. HttpInterceptor使用responseError方法,正确地看到它的状态401,删除任何可能的现有令牌,重定向到/login屏幕,以及return$q.reject(response)
  4. UserService.login()正确地使用错误回调并执行return response
  5. 问题-在我的login.js .login()方法中运行成功回调,而不是第二个错误回调。我有一种感觉,这与本文中讨论的关于承诺链的内容有关,但我的专业知识在这里有局限性,我不太明白下一步应该做什么来告诉链中的下一个回调,上一个回调有错误

这是我的设置:

快递:

authRoutes.js

authRoutes.post("/login", function (req, res) {
    User.findOne({username: req.body.username}, function (err, user) {
        if (err) res.status(500).send(err);
        if (!user) {
            res.status(401).send({success: false, message: "User with the provided username was not found"})
        } else if (user) {
            bcrypt.compare(req.body.password, user.password, function (err, match) {
                if (err) throw (err);
                if (!match) res.status(401).json({success: false, message: "Incorrect password"});
                else {
                    var token = jwt.sign(user, config.secret, {expiresIn: "24h"});
                    res.json({token: token, success: true, message: "Here's your token!"})
                }
            });
        }
    });
});

从调试来看,当我使用不正确的凭据登录时,它正确地击中了res.status(401).send(...)行,所以这部分似乎还可以。

角度:

app.js(包括HttpInterceptor)

var app = angular.module("TodoApp", ["ngRoute"]);
app.factory("AuthInterceptor", ["$q", "$location", "TokenService", function ($q, $location, TokenService) {
    return {
        request: function (config) {
            var token = TokenService.getToken();
            if (token) {
                config.headers = config.headers || {};
                config.headers.Authorization = "Bearer " + token
            }
            return config;
        },
        responseError: function (response) {
            if (response.status === 401) {
                TokenService.removeToken();
                $location.path("/login");
            }
            return $q.reject(response);
        }
    }
}]);
app.config(function ($routeProvider, $httpProvider) {
    $httpProvider.interceptors.push('AuthInterceptor');
    $routeProvider
        .when("/", {
            templateUrl: "landing/landing-page.html"
        });
});

userService.js

var app = angular.module("TodoApp");
app.service("UserService", ["$http", "TokenService", function ($http, TokenService) {
    this.signup = function (user) {
        return $http.post("http://localhost:8080/auth/signup", user).then(function (response) {
            return response;
        }, function (response) {
            return response;
        });
    };
    this.login = function (user) {
        return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
            if (response.data.success) TokenService.setToken(response.data.token);
            return response;
        }, function (response) {
            return response;
        })
    };
    this.isAdmin = function (user) {
        return user.admin;
    };
}]);

login.js(问题似乎在哪里显现)

var app = angular.module("TodoApp");
app.config(function ($routeProvider) {
    $routeProvider
        .when("/login", {
            templateUrl: "auth/login.html",
            controller: "LoginController"
        })
});
app.controller("LoginController", ["$scope", "$http", "$location", "UserService", "TokenService", function ($scope, $http, $location, UserService, TokenService) {
    $scope.login = function (user) {
        UserService.login(user).then(function (response) {
            $location.path("/todo");
        }, function (response) {
            console.log("There was a problem: " + response);
        });
    }
}]);

最后一部分,UserService.login(user).then(function (response) { $location.path("/todo");是正在运行并试图将用户重定向到Todo项目列表的行,当我希望它运行console.log("There was a problem: " + response);行时。。。

就像我上面说的,我有一种感觉,这与链接承诺有关,以及如何在链的中途处理错误,而不是在链中冒泡。不确定我是否需要像我上面提到的网站那样添加.catch()块。即使这是答案,我也不完全确定如何写。

如果有更好的方式我应该组织这件事,我当然也愿意接受建议。我必须把这个教给一班学生,并想确保我教的是良好的实践。

提前感谢您的帮助!

仔细查看代码的这一部分:

this.login = function (user) {
    return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
        if (response.data.success) TokenService.setToken(response.data.token);
        return response;
    }, function (response) {
        return response;
    })
}

在这里,您提供了带有返回值的错误回调,该返回值将传递给promise链中的下一个回调。混乱的根源是,如果您希望错误进一步传播,您仍然需要从回调返回拒绝的抛出承诺。否则,这实际上意味着您已经从错误情况中恢复,流程中的下一步将是成功的。这就是你现在拥有的。

在你的情况下,你要么完全删除错误回调

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
});

或者确保您返回失败的承诺

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    return $q.reject(response);
});

或投掷:

return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
    if (response.data.success) TokenService.setToken(response.data.token);
    return response;
}, function (response) {
    throw new Error(response);
});

您是否尝试在then()调用的错误情况下使用$q.reject

例如

// remember to add $q to deps
this.login = function (user) {
    return $http.post("http://localhost:8080/auth/login", user).then(function (response) {
        if (response.data.success) TokenService.setToken(response.data.token);
        return response;
    }, function (response) {
        $q.reject(response);
    })
};

相关文档:https://docs.angularjs.org/api/ng/service/$q