使用 axios 拦截器时,API 调用循环出现 401 错误

Posted

技术标签:

【中文标题】使用 axios 拦截器时,API 调用循环出现 401 错误【英文标题】:When using axios interceptors, API calls are looping for 401 error 【发布时间】:2021-06-29 09:29:23 【问题描述】:

我正在尝试使用 VueJs 中的拦截器来使用 axios 请求刷新令牌。我已经用拦截器编写了一些逻辑并调度到存储。当令牌过期并且我重新加载页面时,api post 调用会无限尝试形成一个循环。要停止它,我必须关闭浏览器或注销并刷新页面。另一个错误是尝试导入商店时我的 axios.js 文件上的“import/no-cylce”。以下是我的代码,任何建议都有帮助,谢谢。

axios.js


    import axios from 'axios';
    // eslint-disable-next-line import/no-cycle
    import store from '@/store';
    // eslint-disable-next-line import/no-cycle
    
    // axios.defaults.headers.common.Authorization = `Bearer $sessionStorage.getItem('accessToken')`;
    
    const getAPI = axios.create(
      baseURL: 'http://127.0.0.1:5000',
    );
    getAPI.interceptors.response.use(undefined, (error) => 
      if (error.config && error.response.status === 401) 
        const result = 'test interceptor';
        console.log(result);
        store.dispatch('refreshToken')
          // eslint-disable-next-line camelcase
          .then((access_token) => 
            axios.request(
              headers:  Authorization: `Bearer $this.$store.state.accessToken` ,
            );
            console.log(access_token);
          );
      
    );
    // eslint-disable-next-line import/prefer-default-export
    export  getAPI ;

下面是 Vuex store 文件,我创建了一个刷新函数来执行刷新。

import Vue from 'vue';
import Vuex from 'vuex';
// eslint-disable-next-line import/no-cycle
import  getAPI  from '@/axios';
// eslint-disable-next-line camelcase

Vue.use(Vuex);
export default new Vuex.Store(
  state: 
    // accessToken: JSON.parse(localStorage.getItem('access_token')) || null,
    // refreshToken: JSON.parse(localStorage.getItem('refresh_token')) || null,
    accessToken: localStorage.getItem('access_token') || null,
    refreshToken: localStorage.getItem('refresh_token') || null,
    APIData: '',
  ,
  getters: 
    loggedIn(state) 
      return state.accessToken != null;
    ,
  ,
  mutations: 
    // eslint-disable-next-line camelcase
    updateLocalStorage(state,  access_token, refresh_token ) 
      // localStorage.setItem('accessToken', JSON.stringify(access_token));
      // localStorage.setItem('refreshToken', JSON.stringify(refresh_token));
      localStorage.setItem('access_token', access_token);
      localStorage.setItem('refresh_token', refresh_token);
      // eslint-disable-next-line camelcase
      state.accessToken = access_token;
      // eslint-disable-next-line camelcase
      state.refreshToken = refresh_token;
    ,
    // eslint-disable-next-line camelcase
    updateAccessToken(state, access_token) 
      // eslint-disable-next-line camelcase
      state.accessToken = access_token;
    ,
    destroyToken(state) 
      state.accessToken = null;
      state.refreshToken = null;
    ,
  ,
  actions: 
    userLogin(context, credentials) 
      return new Promise((resolve, reject) => 
        getAPI.post('/login', 
          email: credentials.email,
          password: credentials.password,
        )
          .then((response) => 
            context.commit('updateLocalStorage',  access_token: response.data.access_token, refresh_token: response.data.refresh_token );
            resolve();
            console.log('\'access token\'', response.data.access_token);
            console.log('\'refresh token\'', response.data.refresh_token);
            // console.log(context.state.accessToken);
            // console.log(context.state.refreshToken);
          )
          .catch((error) => 
            reject(error);
          );
      );
    ,
    userLogout(context) 
      if (context.getters.loggedIn) 
        // context.commit('updateLocalStorage', null);
        context.commit('destroyToken');
      
    ,
    refreshToken(context) 
      return new Promise((resolve, reject) => 
        console.log(context.state.refreshToken);
        getAPI.post('/refresh', 
          // refresh_token: context.state.refreshToken,
          headers:  Authorization: `Bearer $context.state.refreshToken` ,
        )
          .then((response) => 
            console.log('New access token granted');
            context.commit('updateAccessToken', response.data.access_token);
            console.log(context.state.accessToken);
            resolve(response.data.access_token);
          )
          .catch((error) => 
            console.log('\'error in refresh:\'', error);
            reject(error);
          );
      );
    ,
  ,
);

以下是受保护数据的视图文件。 关于.vue

 created() 
    getAPI.get('/userList', 
      // eslint-disable-next-line no-undef
      headers:  Authorization: `Bearer $this.$store.state.accessToken` ,
    ,
    console.log(`Bearer $this.$store.state.accessToken`))
      .then((response) => 
        this.$store.state.APIData = response.data;
        console.log(response.data);
      )
      .catch((error) => 
        console.log(error);
      );
  ,

【问题讨论】:

【参考方案1】:

另外,我更早收到此错误。我用axiosAuth代替axio

前-:

 const getAPI = axiosAuth.create(
      baseURL: 'http://127.0.0.1:5000',
    );

【讨论】:

它不工作,我的 api 调用仍在循环。任何参考代码?

以上是关于使用 axios 拦截器时,API 调用循环出现 401 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何限制/速率限制请求以防止 Axios 出现 429 错误

Axios 拦截器不会在页面加载时拦截

axios拦截器和异步登录

React Axios API 调用与数组循环给出错误的顺序?

使用带有 JWT 令牌的 Axios 对 Redux saga 产生调用的无限循环

Axios源码解析:拦截器