【发布时间】:2018-06-22 12:34:39
【问题描述】:
我正在使用 apollo 客户端在我的组件中进行查询。它由 2 个查询组成。在它给我一个 401 错误后,我如何阻止它向它发送另一个查询。我正在使用 onError Apollo Link Error 来监听错误。但是,它调度了两个查询,我无法停止下一个查询。
【问题讨论】:
标签: apollo react-apollo apollo-client
我正在使用 apollo 客户端在我的组件中进行查询。它由 2 个查询组成。在它给我一个 401 错误后,我如何阻止它向它发送另一个查询。我正在使用 onError Apollo Link Error 来监听错误。但是,它调度了两个查询,我无法停止下一个查询。
【问题讨论】:
标签: apollo react-apollo apollo-client
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 个链接可能更容易。一个设置传出身份验证上下文,另一个捕获响应并处理身份验证错误。
【讨论】: