【问题标题】:Stop subsequent queries in apollo after 401 has been returned?返回 401 后停止 apollo 中的后续查询?
【发布时间】:2018-06-22 12:34:39
【问题描述】:

我正在使用 apollo 客户端在我的组件中进行查询。它由 2 个查询组成。在它给我一个 401 错误后,我如何阻止它向它发送另一个查询。我正在使用 onError Apollo Link Error 来监听错误。但是,它调度了两个查询,我无法停止下一个查询。

【问题讨论】:

    标签: apollo react-apollo apollo-client


    【解决方案1】:

    Apollo Link Error 允许您拦截和处理查询或网络错误。但是,它不提供管理后续请求的机会。为此,您需要创建自己的链接。

    我过去使用过类似以下的东西。下面的示例专门处理带有刷新令牌的不记名身份验证,但同样的原理可用于处理任何身份验证失败。

    import { ApolloLink, Observable } from 'apollo-link';
    
    const isAuthError = (statusCode: number) => [401, 403].includes(statusCode);
    
    const authLink = new ApolloLink((operation, forward) => {
      // Set outgoing Authorization headers
      const setHeaders = () =>
        operation.setContext(({ store, headers, ...rest }) => {
           // get the authentication token from local storage if it exists
           const token = localStorage.getItem('token');
           // return the headers to the context so httpLink can read them
    
          return {
            ...rest,
            store,
            headers: {
              ...headers,
              authorization: `Bearer ${token}`
            }
          };
        });
    
      setHeaders();
    
      return new Observable(obs => {
        const subscriber = {
          next: obs.next.bind(obs),
          // Handle auth errors. Only network or runtime errors appear here.
          error: error => {
            if (isAuthError(error.statusCode)) {
              // Trigger an auth refresh.
                    refreshTokenOrLogin()
                      .then(setHeaders)
                      .then(() => forward(operation).subscribe(subscriber));
                  }
                }
              });
            } else {
              obs.error(error);
            }
          },
          complete: obs.complete.bind(obs)
        };
    
        forward(operation).subscribe(subscriber);
      });
    });
    

    第一部分设置由Apollo 记录的身份验证上下文。您应该将其替换为您正在使用的任何身份验证机制。

    operation.setContext(({ store, headers, ...rest }) => {
       // get the authentication token from local storage if it exists
       const token = localStorage.getItem('token');
       // return the headers to the context so httpLink can read them
    
      return {
        ...rest,
        store,
        headers: {
          ...headers,
          authorization: `Bearer ${token}`
        }
      };
    });
    

    像这样的非终止链接必须返回一个 observable。这使我们能够像 Apollo Link Error 一样捕获任何网络错误,只是我们现在可以处理随后发生的事情。在这种情况下,我们创建并返回一个带有错误处理程序的新可观察对象,该处理程序将触发身份验证令牌刷新,然后重试请求。下一个和完成处理程序被传递到下一个未触及的链接。

    new Observable(obs => {
        const subscriber = {
          next: obs.next.bind(obs),
          // Handle auth errors. Only network or runtime errors appear here.
          error: error => {
            if (isAuthError(error.statusCode)) {
              // Trigger an auth refresh.
                    refreshTokenOrLogin()
                      .then(setHeaders)
                      .then(() => 
                        // We can now retry the request following a successful token refresh.
                        forward(operation).subscribe(subscriber)
                      );
                  }
                }
              });
            } else {
              obs.error(error);
            }
          },
          complete: obs.complete.bind(obs)
        };
    
        forward(operation).subscribe(subscriber);
      });
    

    将其视为 2 个链接可能更容易。一个设置传出身份验证上下文,另一个捕获响应并处理身份验证错误。

    【讨论】:

    • 如果您有两个几乎同时的请求,但出现身份验证错误会怎样?它会在竞争条件下触发多次令牌刷新吗?
    猜你喜欢
    • 2017-12-27
    • 2017-07-30
    • 1970-01-01
    • 2017-03-21
    • 2018-04-27
    • 2016-09-19
    • 2017-05-07
    • 2019-07-25
    • 2021-11-02
    相关资源
    最近更新 更多