拦截器上的Axios多个请求

时间:2019-01-17 17:16:50

标签: javascript asynchronous concurrency axios race-condition

我正在使用我的React应用中的库 axios
我的拦截器有问题。

我的问题是,我有三个同时发生的请求,而我没有令牌,拦截器三次调用getUserRandomToken,我希望拦截器将等到从第一个请求中获得令牌时,然后继续其他人。

附言他具有到期日期的令牌,因此我也要检查它,如果到期日期无效,则需要创建一个新令牌。

这是拦截器:

axios.interceptors.request.use(
  config => {
    /*I'm getting the token from the local storage
    If there is any add it to the header for each request*/
    if (tokenExist()) {
      config.headers.common["token"] = "...";
      return config;
    }
    /*If there is no token i need to generate it
     every time create a random token, this is a axios get request*/
    getUserRandomToken()
      .then(res => {
        /*add the token to the header*/
        config.headers.common["token"] = res;
        return config;
      })
      .catch(err => {
        console.log(err);
      });
  },
  function(error) {
    // Do something with request error
    return Promise.reject(error);
  }
);

3 个答案:

答案 0 :(得分:0)

将处理代币生成的单例对象怎么样?与此类似:

const tokenGenerator ={
  getTokenPromise: null,
  token: null,
  getToken(){
    if (!this.getTokenPromise){
      this.getTokenPromise = new Promise(resolve=>{
        /*supposed to be a http request*/
        if (!this.token){
          setTimeout(()=>{
            this.token = 'generated';
            resolve(this.token);
          },0)
        }else{
          resolve(this.token);
        }
      })
    }
    return this.getTokenPromise;
  }

您可以从拦截器中引用相同的对象。

请参阅示例:JS FIddle 参考:reference

答案 1 :(得分:0)

您可以将Promise从拦截器回调返回到“等待”,直到承诺完整文件为止(这将适合您的情况)。看看这个例子:

function axiosCall () {
  return new Promise((resolve, reject) => {
    Axios.post(URL, {apiKey}).then((response) => {
      resolve(response.data.message);
    }).catch((error) => {
      reject(error);
    });
  });
}

instance.interceptors.request.use((config) => {
  return axiosCall().then((tokenResponse) => {
    setWebCreds(tokenResponse);
    config.headers.Authorization = `Bearer ${tokenResponse}`;
    return Promise.resolve(config)
  }).catch(error => {
    // decide what to do if you can't get your token
  })
}, (error) => {
  return Promise.reject(error);
});

此处有更多详细信息:https://github.com/axios/axios/issues/754

答案 2 :(得分:0)

执行某些任务的以下代码:

  1. 在 401 上更新令牌
  2. 在令牌刷新时创建一个失败请求队列。
  3. 令牌刷新后恢复原始请求。
  4. 一旦特殊请求被赋予 200,就将其从队列中移除。

Config.js

<块引用>
import axios from 'axios';
import { AsyncStorage } from 'react-native';
import { stateFunctions } from '../../src/sharedcomponent/static';

const APIKit = axios.create({
    baseURL: '',
    timeout: 10000,
    withCredentials: true,
});
const requestArray = [];
// Interceptor for Request
export const setClientToken = token => {
    APIKit.interceptors.request.use(
        async config => {
            console.log('Interceptor calling');
            let userToken = await AsyncStorage.getItem('userToken');
            userToken = JSON.parse(userToken);
            config.headers = {
                'Authorization': `Bearer ${userToken}`,
                'Accept': 'application/json',
                "Content-Type": "application/json",
                "Cache-Control": "no-cache",
            }
            //   console.log('caling ' , config)
            return config;
        },
        error => {
            Promise.reject(error)
        });
};


// Interceptor for Response
APIKit.interceptors.response.use(
    function (response) {
        if (requestArray.length != 0) {
            requestArray.forEach(function (x, i) {
                if (response.config.url == x.url) {
                    requestArray.splice(i, 1);
                }
            });
        }
        return response;
    },
    function (error) {
        const originalRequest = error.config;
        requestArray.push(originalRequest);
        let reqData = "username=" + number + "&password=" + pin + "&grant_type=password" + "&AppType=2" + "&FcmToken=null";
        // console.log('error ' , error);
        if (error.message === "Request failed with status code 401" || error.statuscode === 401) {
            if (!originalRequest._retry) {
                originalRequest._retry = true;
                return axios({
                    method: 'post',
                    url: '/api/login',
                    data: reqData,
                    headers: {
                        "Content-Type": "application/x-www-form-urlencoded",
                        "Cache-Control": "no-cache",
                    }
                })
                    .then(res => {
                        let response = res.data;
                        console.log('successfull Login', response)
                        if (res.data.StatusCode == 200) {
                            AsyncStorage.setItem('userToken', JSON.stringify(response.access_token));
                            stateFunctions.UserId = response.UserId;
                            stateFunctions.CustomerContactID = response.CustomerContactID;
                            let obj = {
                                access_token: response.access_token,
                                token_type: response.token_type,
                                expires_in: response.expires_in,
                                UserId: response.UserId,
                                CustomerContactID: response.CustomerContactID,
                                Mobile: response.Mobile,
                                StatusCode: response.StatusCode
                            }
                            AsyncStorage.setItem('logindetail', JSON.stringify(obj));
                            if (requestArray.length != 0) {
                                requestArray.forEach(x => {
                                    try {
                                        console.log(x, "request Url");
                                        x.headers.Authorization = `Bearer ${response.access_token}`;
                                        x.headers["Content-Type"] = "application/x-www-form-urlencoded";
                                        APIKit.defaults.headers.common["Authorization"] = `Bearer${response.access_token}`;
                                        APIKit(x)
                                    } catch (e) {
                                        console.log(e)
                                    }
                                });
                            }
                            return APIKit(originalRequest);
                        }
                    })
                    .catch(err => {
                        console.log(err);
                    });
            }
        }
        return Promise.reject(error);
    }
);

export default APIKit;

Home.js

<块引用>
gettingToken = async () => {
    let userToken = await AsyncStorage.getItem('userToken');
    userToken = JSON.parse(userToken);
    await setClientToken(userToken);
}