【问题标题】:Axios Reponse Interceptor : unable to handle an expired refresh_token (401)Axios 响应拦截器:无法处理过期的刷新令牌 (401)
【发布时间】:2018-06-14 12:17:41
【问题描述】:

我的 axios 响应中有以下拦截器:

window.axios.interceptors.response.use(
  response => {
    return response;
  },
  error => {
    let errorResponse = error.response;
    if (errorResponse.status === 401 && errorResponse.config && !errorResponse.config.__isRetryRequest) {
      return this._getAuthToken()
        .then(response => {
          this.setToken(response.data.access_token, response.data.refresh_token);
          errorResponse.config.__isRetryRequest = true;
          errorResponse.config.headers['Authorization'] = 'Bearer ' + response.data.access_token;
          return window.axios(errorResponse.config);
        }).catch(error => {
          return Promise.reject(error);
        });
    }
    return Promise.reject(error);
  }
);

_getAuthToken 方法是:

_getAuthToken() {
    if (!this.authTokenRequest) {
        this.authTokenRequest = window.axios.post('/api/refresh_token', {
            'refresh_token': localStorage.getItem('refresh_token')
        });
        this.authTokenRequest.then(response => {
            this.authTokenRequest = null;
        }).catch(error => {
            this.authTokenRequest = null;
        });
    }

    return this.authTokenRequest;
}

代码深受https://github.com/axios/axios/issues/266#issuecomment-335420598 的启发。

总结:当用户调用 API 并且他的 access_token 已过期(API 返回 401 代码)时,应用程序调用 /api/refresh_token 端点以获取新的 access_token。如果在进行此调用时 refresh_token 仍然有效,则一切正常:我得到一个新的 access_token 和一个新的 refresh_token,并且用户请求的初始 API 调用再次进行并正确返回。

当 refresh_token 也过期时会出现问题。
在这种情况下,对 /api/refresh_token 的调用返回 401 并且没有任何反应。我尝试了几件事,但无法将用户重定向到应用程序的登录页面。
我发现在这种情况下,_getAuthToken 方法中的 if (!this.authTokenRequest) 语句会返回一个从未解决的未决 Promise。我不明白为什么这是一个承诺。在我看来它应该是空的......

我是 Promises 的新手,所以我可能会遗漏一些东西! 感谢您的帮助!

编辑:

我可能找到了一种更简单的方法来处理这个问题:当我调用 /api/refresh_token 端点时,使用 axios.interceptors.response.eject() 禁用拦截器,然后重新启用它。

代码:

createAxiosResponseInterceptor() {
        this.axiosResponseInterceptor = window.axios.interceptors.response.use(
            response => {
                return response;
            },
            error => {
                let errorResponse = error.response;
                if (errorResponse.status === 401) {
                    window.axios.interceptors.response.eject(this.axiosResponseInterceptor);
                    return window.axios.post('/api/refresh_token', {
                        'refresh_token': this._getToken('refresh_token')
                    }).then(response => {
                        this.setToken(response.data.access_token, response.data.refresh_token);
                        errorResponse.config.headers['Authorization'] = 'Bearer ' + response.data.access_token;
                        this.createAxiosResponseInterceptor();
                        return window.axios(errorResponse.config);
                    }).catch(error => {
                        this.destroyToken();
                        this.createAxiosResponseInterceptor();
                        this.router.push('/login');
                        return Promise.reject(error);
                    });
                }
                return Promise.reject(error);
            }
        );
    },

它看起来好还是坏?任何建议或评论表示赞赏。

【问题讨论】:

    标签: laravel vue.js es6-promise axios laravel-passport


    【解决方案1】:

    您的最后一个解决方案看起来不错。如果我处于相同的情况,我会想出与您类似的实现。

    我发现在这种情况下,_getAuthToken 方法中的 if (!this.authTokenRequest) 语句会返回一个从未解决的未决 Promise。我不明白为什么这是一个承诺。在我看来它应该是空的......

    这是因为代码中的this.authTokenRequest 刚刚分配了从window.axios.post 创建的Promise。 Promise 是一种对象处理类型的惰性求值,因此您在 then 中实现的过程在 Promise 解决之前不会执行。

    JavaScript 为我们提供了 Promise 对象作为一种异步事件处理程序,它使我们能够将流程实现为 then 链,该链将被执行以响应异步结果的结果。 HTTP 请求总是不可预测的,因为 HTTP 请求有时会消耗我们预期的更多时间,有时也不会。当我们使用 HTTP 请求时,总是使用 Promise,以便通过事件处理程序处理它的异步响应。

    在 ES2015 语法中,您可以使用 async/await 语法实现函数来处理 Promise 对象,因为它看起来是同步的。

    【讨论】:

    • 谢谢@IzumiSy。最后,我认为我的最后一个解决方案更好:更少的代码,更少的异步,最重要的是,它有效!我很惊讶我没有找到任何使用 axios.interceptors.response.eject 方法来处理这个问题的例子。我发现的所有示例都使用了 Promises,但我从未设法让它们工作。如果我的解决方案可以帮助其他人,我会很高兴!
    猜你喜欢
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2021-02-11
    • 2022-01-25
    • 2018-06-02
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多