我目前正在使用Express构建微服务。为了检索第二个微服务的访问令牌,我通过axios将HTTP POST请求发送到令牌端点。为了减少流量并简化令牌管理,仅当当前令牌到期时才请求新令牌。如果由于前一个令牌过期而请求一个新令牌,则所有调用者都应等待该令牌,而不是请求多个新令牌。为此,我实现了以下实例化为单例的类Auth
:
class Auth {
getToken() {
if (this.token && !isExpired(this.token)) {
return Promise.resolve(this.token);
}
if (!this.tokenPromise) {
this.tokenPromise = axios
.post(...)
.then(response => {
console.log("received token");
this.tokenPromise = null;
this.token = response.data.token;
return response.data.token;
})
.catch(() => null);
}
return this.tokenPromise;
}
}
// export Auth class as singleton
module.exports = new Auth();
但是,当我调用getToken
时,返回的承诺将永远无法解析,并且语句console.log("received token");
也不会被调用。为了进行测试,我更改了代码并返回了另一个Promise而不是axios promise:
class Auth {
getToken() {
if (this.token && !isExpired(this.token)) {
return Promise.resolve(this.token);
}
if (!this.tokenPromise) {
this.tokenPromise = axios
.post(...)
.then(response => {
console.log("received token");
this.tokenPromise = null;
this.token = response.data.token;
return response.data.token;
})
.catch(() => null);
this.secondPromise = Promise.resolve("fakeToken");
}
return this.secondPromise;
}
}
// export Auth class as singleton
module.exports = new Auth();
在这种情况下,调用getToken
和console.log("received token");
时,返回的承诺和axios承诺都会解析。是什么原因造成的?我该如何达到预期的行为?
最少的工作示例
在创建此最小工作示例期间,事实证明,仅当从axios拦截器调用getToken()
方法时才出现问题(创建异步拦截器时我遵循了这些examples)。您可以使用以下最小工作示例重现该问题:
mwe.js:
const axios = require("axios");
class Auth {
getToken() {
if (!this.tokenPromise) {
console.log("get token");
this.tokenPromise = axios
.post("https://example.com")
.then((response) => {
console.log("received token");
this.tokenPromise = null;
return response;
})
.catch((err) => {
console.log("err", err);
this.tokenPromise = null;
return null;
});
}
return this.tokenPromise;
}
}
const auth = new Auth();
axios.interceptors.request.use(
async (config) => {
const token = await auth.getToken();
config.headers.Authorization = `Bearer ${token}`;
return config;
},
(error) => {
console.log("interceptor error", error);
}
);
axios.get("https://example.com");
package.json:
{
"name": "mwe",
"version": "1.0.0",
"description": "minimum working example",
"main": "mwe.js",
"scripts": {},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.19.2"
}
}
运行node mwe.js
时会记录消息"get token"
,但不会记录"received token"
。