401返回后,在apollo中停止后续查询?

时间:2018-01-13 03:01:38

标签: apollo react-apollo apollo-client

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

1 个答案:

答案 0 :(得分:1)

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

我过去曾经使用过类似的东西。以下示例专门处理带有刷新令牌的承载auth,但可以使用相同的原则来处理任何身份验证失败。

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那样捕获任何网络错误,除了我们现在可以处理随后发生的事情。在这种情况下,我们创建并返回一个带有错误处理程序的新observable,它将触发auth令牌刷新,然后重试请求。下一个和完成处理程序将被传递到未触及的下一个链接。

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个链接可能更容易。一个设置传出的auth上下文,另一个设置捕获响应并处理auth错误。