reactjs - Apollo 客户端异步刷新令牌
问题描述
当发生未经身份验证的错误时,我一直在努力异步刷新 Apollo 客户端中的令牌。我已经查看了这方面的几个资源,比如 StackOverflow 答案、这个Github 问题和这个博客文章。
主要是在获得新令牌之后,在重试失败的请求之前等待。看了上面博客的评论和Github issue的评论,好像很多人都成功解决了这个问题,但是我用新的token拿到数据,retry完成后,表示重试是仍然使用旧令牌完成,所以它失败了。
这是执行刷新突变的函数。
export const getNewToken = (client) => {
const refreshToken = getRefreshToken();
return client.mutate({
mutation: REFRESH_TOKEN,
variables: { refreshToken },
});
};
这是Auth Link,我做了一个console.log
令牌,以了解使用了哪个令牌。
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem("token");
console.log("Token in auth link: ", token);
return {
headers: {
...headers,
authorization: token ? `JWT ${token}` : "",
},
};
});
然后在 Apollo 的onError
函数中,我尝试重新创建上面链接博客中的第三个示例:
if (token && refreshToken) {
return fromPromise(
getNewToken(client)
.then(({ data: { refreshToken } }) => {
console.log("Promise data: ", refreshToken);
localStorage.setItem("token", refreshToken.token);
localStorage.setItem("refreshToken", refreshToken.refreshToken);
return refreshToken.token;
})
.catch((error) => {
// Handle token refresh errors e.g clear stored tokens, redirect to login, ...
console.log("Error after setting token: ", error);
return;
})
)
.filter((value) => {
console.log("In filter: ", value);
return Boolean(value);
})
.flatMap(() => {
console.log("In flat map");
// retry the request, returning the new observable
return forward(operation);
});
}
执行这个有两个问题: 1. filter
andflatMap
函数根本没有被调用。2. 在authLink
使用旧令牌记录呼叫后收到新令牌。这意味着forward(operation)
不等待新令牌。
我还尝试了来自链接博客的并发请求。那里还有更多内容,所以这是src/index.js
一个要点
https://gist.github.com/bzhr/531e1c25a4960fcd06ec06d8b21f143b
这里forward$.flatMap
根本不会被称为。和上面的例子一样的问题。
我不确定我的错误在哪里,因为很多人在博客上评论说它对他们有用。我已经多次检查我的代码。我需要一些帮助来调试它。主要是等待重试,直到新令牌准备好。
解决方案
我也是这个面临的问题,但终于让它工作了。
- 而不是 fromPromise。我使用了一个 util 方法,它使用 Observables 来订阅我们的 Promise .then 方法。
const _promiseToObservable = promiseFunc =>
new Observable(subscriber => {
promiseFunc.then(
value => {
if (subscriber.closed) return;
subscriber.next(value);
subscriber.complete();
},
err => subscriber.error(err),
);
return subscriber; // this line can removed, as per next comment
});
之后在 OnError 中使用此 util 方法而不是 fromPromise 调用您的 getNewToken() 方法。
- 如果您使用 for GraphQlErrors,请删除 for 循环。取第一个数组元素 graphQlErrors[0],它通常包含我们的错误数据。
进行这两个更改对我有用。