将Axios承诺返还给多个呼叫者

时间:2020-04-08 10:17:13

标签: javascript node.js express promise axios

我目前正在使用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();

在这种情况下,调用getTokenconsole.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"

0 个答案:

没有答案