如何使用 React Apollo Client 处理 HTTP 状态错误

How to handle HTTP status errors with React Apollo Client

我在后端使用 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,您可以使用 ? shorthand .例如:

if(a){
  if(a.b){
    if(a.b.c){
      // ...
    }
  }
}

可以简化为:

if(a?.b?.c){
 // ...
}