身份验证-$http'调用了s.then()成功回调,而不是错误回调
Authentication - $http's .then() success callback called instead of error callback
这可能只是因为我对如何在MEAN堆栈应用程序中最好地进行身份验证存在误解,或者我对promise和$http的.then()
方法的工作原理缺乏了解,但每当我试图使用不正确的凭据向后端Node服务器进行身份验证时,它都会调用$http的.then()
方法的成功回调,而不是错误回调。这是我的设置:
我使用jsonwebtoken
和express-jwt
包,AngularJS拦截器添加令牌以请求和检查状态401 responseErrors,设置/删除等JWT的TokenService,以及处理登录、注销等的UserService。
从调试开始,发生了以下情况:
- 发出登录请求
- 服务器捕获请求,查找指定的用户,但在数据库中找不到他们。返回401错误,JSON对象包括错误消息等
- HttpInterceptor使用
responseError
方法,正确地看到它的状态401,删除任何可能的现有令牌,重定向到/login
屏幕,以及return
的$q.reject(response)
UserService.login()
正确地使用错误回调并执行return response
-
问题-在我的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
- 成功回调永远不会被JSONP请求调用
- 查询后websql成功回调无法访问变量
- 在$q服务中捕获拒绝而不触发成功回调
- 如何从ajax成功回调函数中读取javascript变量
- bookmarklet中的jQuery.getScript()进行回调,但没有成功执行插件
- $http服务未触发成功或错误回调
- 在AJAX中使用window.location.replace'成功'回调
- AJAX成功回调-执行javascript时出现问题
- 当使用命名函数作为jquery ajax成功回调时,我需要括号吗
- jQuery$.post可以在chrome、safari中工作,但不能在FF中工作(声明成功回调函数未定义)
- Yii ajaxbutton : 如何在成功回调函数中获取 $(this)
- 角承诺的“then”函数的成功回调的词汇范围是什么?
- 解析查询.首次成功/错误 间歇性不调用回调
- 承诺中的成功回调不会发生$http
- AJAX内部回调成功
- AJAX 的回调(成功?)函数
- 流星:从服务器回调成功后写入数据库
- 回调成功后,不能将字符串推入数组
- Ajax, post数据但不回调成功
- 如何使循环等待回调成功