我有一个简单的登录应用程序,在后端使用apollo-server-express。如果用户输入了无效的用户名或密码,它会抛出401 Unauthorized异常,如下所示:
async login(username: string, password: string) {
const user = await this.userService.findOneByUsername(username);
if (!user) {
throw new UnauthorizedException("The username doesn't exists");
}
const validPassword = bcrypt.compareSync(password, user.password);
if (!validPassword) {
throw new UnauthorizedException('The password is incorrect');
}
return user;
}
现在,在我的React客户端中,我使用Apollo client来消费服务。我做了这样的登录:
const [login, { error, loading }] = useLoginMutation({
variables: {
username,
password,
},
});
const onFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const response = await login();
if (response) {
if (response.data) {
localStorage.setItem("user", response.data.login.jwt);
addUser(response.data.login.user);
}
}
};
现在,当我输入错误的用户名或密码时,在后端会抛出异常,但它会使React应用程序停止。这个问题可以通过在login()方法之后添加catch语句来解决,如下所示:
const response = await login().catch(e => { });
但是我想知道是否有一种优雅的方法可以在客户端捕获异常或在服务器中抛出异常。在REST服务错误,如401不使应用程序停止,请求只失败,但应用程序仍在运行,但我是新的GraphQL,我想知道如果不是这样的GraphQL服务。是否有更好的方法来处理或抛出GraphQL和Apollo的Http错误?
问题
async/await
语句必须在try/catch
块中。更多关于MDN文档。
then/catch
是另一种处理异步承诺的方法,但结果与async/await
相同,因此不要将它们混合在一起。
的解决方案在当前的实现(async/await
)中,您需要将异步获取函数包装在try/catch
块中以控制所有副作用(成功和失败的场景)。
const onFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
try {
const response = await login();
if (response?.data) {
localStorage.setItem("user", response.data.login.jwt);
addUser(response.data.login.user);
}
} catch (error) {
// do a proper action in error cases
const myErrorStatus = error.response?.status
if(myErrorStatus === 401) {
// do this
} else if (myErrorStatus === 404) {
// do this
}
}
};
(可选):
注意:代替使用嵌套的if
块来检查response
,您可以使用?
简写。例如:
if(a){
if(a.b){
if(a.b.c){
// ...
}
}
}
可以简化为:
if(a?.b?.c){
// ...
}