In project development, we often encounter the problem of token failure and unable to request data when requesting data. In case of such problems, the general processing method is to jump to the login page and log in again to obtain the token. If you ignore the user's mood, it's not impossible to deal with it in this way.
But this is not the effect I want. As an ideal front-end, we should have higher requirements. I expect to re request a valid token when the interface expires, and use the new token to retry the last failed request.
Solution ideas
This article takes axios as an example, so we need to write on the request interceptor axios.interceptors.response.use(). My backend does not return the status code in the interface, so I do it in the error handler of the interceptor
Specific ideas:
- Judge whether the status code (error.request.status) is 401 in the error processing function of axios.interceptors.response.use() interceptor
- If 401 records the config = error.config of the current request and return s a request for updatetoken (the request to get a new token)
- In order to avoid new requests coming in during the process of requesting a new token and re requesting a token again, resulting in the invalidation of a new token, we need a tag variable to lock it to ensure that new tokens will not be affected by multiple requests.
- Set a queue to store all requests before the token is updated and completed in the form of a function to be executed
- Update the cached token in the updateToken callback function, and update the token in the config to be retried. At the same time, in order to avoid the impact of the cache, add a timestamp parameter to the requested address
- Enable the function to be retried in the queue. After enabling, the queue will be empty. Retry the current config instance
The token in the project exists in localStorage. The basic result of request.js is as follows:
/** * Method statement, * setToken() Method of storing token in localStorage * getToken() Method for obtaining token in localStorage * removeToken() Method of clearing token in localStorage * updateToken() Request to get a new token * */ // 1. Declaration examples const service = axios.create({ timeout: 50000 // request timeout }) // Are you refreshing your tags let isRefreshing = false // Retry Queue let requests = [] service.interceptors.response.use( (response) => { return response }, (error) => { if (error.request.status === 401) { // Record instance const config = error.config // Judge whether the token is being updated if(!isRefreshing) { // Change tag status isRefreshing = true // You must return before requesting a token function, otherwise you can retry the successful data, // It will not be returned to the response of the request data function return updateToken().then(res => { setToken(res.data.access_token) // Retry the request stored in the queue requests.forEach(cb => cb()) // Empty queue requests = [] return service(config) }).catch(()=> { // Failed to request a new token. Jump to the login page }).finally(() => { // After the token processing is completed, the token status must be changed, otherwise the token will be re requested all the time isRefreshing = false }) } else { return new Promise((resolve) => { // Put the resolve into the queue, save it in a function form, and execute it directly after the token is refreshed requests.push(() => { // //Add a timestamp to the url to avoid the impact of request caching if( config.url.indexOf('?') > -1) { config.url = config.url + '&n='+ new Date().getTime() } else { config.url = config.url + '?n='+ new Date().getTime() } config.headers['Authorization'] = getToken() resolve(service(config)) }) }) } } else { return Promise.reject(error) } }) export default service
Implementation reference: How axios uses promise to refresh token s painlessly