2017-07-08 49 views
1

我有一个axios调用的请求拦截器。它检查我的jwt令牌并在必要时调用刷新。Axios请求拦截器等到ajax调用完成

axios.interceptors.request.use((config) =>{ 

    const state = store.getState(); // get renewed state 
    const time = Math.floor(new Date().getTime()/1000); 

    if( 
     ! state.app.jwtRefreshOnRequest 
     && time >= state.jwt.expires - 120 
     && state.jwt.refresh_before > time 
    ){ // expiring in 2 min. refresh  

     //dispatch({type: 'JWT_REFRESH_REQUEST'}); 
     axios.get(API_BASE_URL + '/auth/refresh') 
      .then(function(response){ 
       // dispatch({type: 'JWT_REFRESH_SUCCESS', payload: response.data}); 
       axios(config).then(resolve, reject); 
      }) 
      .catch(function(err){    
       reject(err); 
     }); 

    }  

    return config; 
}); 

此代码调用正确的刷新并保存新的令牌,但原来的呼叫不持有,直到拦截请求完成的,所以使用了过期的令牌。

所以,我想我需要从拦截器进行同步调用。

回答

7

避免对HTTP请求进行同步调用,因为它们只会让您的应用程序挂起。

你需要做的是使调用代码异步 - 任何回调,承诺或异步相关的一般规则是,一旦你是异步的,一切都需要异步。

这里,axios.get返回一个Promise-一个跟踪异步HTTP请求并在其完成后解析的对象。你需要返回,而不是config

我们通过返回一个新的Promise来做到这一点 - 如果需要一个新的令牌的HTTP请求,它会等待它,如果没有,它可以立即resolve

axios.interceptors.request.use(config => 
    new Promise((resolve, reject) => { 
     // ... your code ... 

     axios.get(API_BASE_URL + '/auth/refresh') 
      .then(response => { 
       // Get your config from the response 
       const newConfig = getConfigFromResponse(response); 

       // Resolve the promise 
       resolve(newConfig); 
      }, reject); 

     // Or when you don't need an HTTP request just resolve 
     resolve(config); 
    }) 
}); 

每当你看到then你处理Promise,一旦你一切需要返回Promise

这是容易,如果你可以用async/await - 如果需要支持传统的用户可以通过现代的浏览器,并支持transpilable新的关键字。有了这些,您只需将Promise呼叫与await关键字内联即可。

axios.interceptors.request.use(async config => 

    // ... your code ... 

    if(/* We need to get the async token */) { 
     const response = await axios.get(API_BASE_URL + '/auth/refresh'); 
     config = getConfigFromResponse(response); 
    } 

    return config; 
}); 
+1

谢谢,它工作。我从你的回答中学到了很多东西:) – Sisir