我有一个文件request.js,其中包含axios ajax请求的包装。我正在从多个React组件中调用请求函数,当请求之一失败时,我想刷新令牌并再次重试所有失败的请求。我可以使用拦截器,但是我不知道如何实现它。请帮忙。
request.js
var client = axios.create({ baseURL: 'http://192.168.1.3:3000', headers: { appID: 8, version: "1.1.0", empID: localStorage.getItem('empID'), token: localStorage.getItem('accessToken') } }); const request = function(options) { const onSuccess = function(response) { console.debug('Request Successful!', response); return response.data; } const onError = function(error) { console.error('Request Failed:', error.config); if (error.response) { console.error('Status:', error.response.status); console.error('Data:', error.response.data); console.error('Headers:', error.response.headers); } else { console.error('Error Message:', error.message); } return Promise.reject(error.response || error.message); } return client(options) .then(onSuccess) .catch(onError); options } export default request;
我用以下代码工作
import axios from 'axios'; import config from '../../configuration.json'; import qs from 'qs'; const baseURL = config['baseUrl_local']; let authTokenRequest; /** * @description axios instance for ajax requests */ var client = axios.create({ baseURL: baseURL, headers: { appID: 8, version: "1.1.0", empID: localStorage.getItem('empID'), token: localStorage.getItem('accessToken') } }); /** * @description this method calls a requestNewToken method to issue a new token to the client */ function getAuthToken() { if (!authTokenRequest) { authTokenRequest = requestNewToken(); authTokenRequest.then(resetAuthTokenRequest, resetAuthTokenRequest); } return authTokenRequest; } /** * @description this method requests the server to issue a new token, the server response is updated in local storage accessToken */ function requestNewToken() { var newToken = request({ method: "post", url: '/sign-in', data: qs.stringify({ "userName":localStorage.getItem('userName'), "password":localStorage.getItem('password') }) }).then((res)=>{ if(res.status == "success"){ localStorage.setItem('accessToken',res.data.accessToken); //if featureArray is present in response object, update the featureArray in local storage if(res.data.features){ localStorage.setItem( 'featureArray', JSON.stringify(res.data.features)); } client = axios.create({ baseURL: baseURL, headers: { appID: 8, version: "1.1.0", empID: localStorage.getItem('empID'), token: localStorage.getItem('accessToken') } }); } else { window.location = "/logout"; } }); return newToken; } function resetAuthTokenRequest() { authTokenRequest = null; } /** * @description if any of the API gets 401 status code, this method calls getAuthToken method to renew accessToken * updates the error configuration and retries all failed requests again */ client.interceptors.response.use(undefined, err => { const error = err.response; // if error is 401 if (error.status===401 && error.config && !error.config.__isRetryRequest) { // request for a new token return getAuthToken().then(response => { // update the error config with new token error.config.__isRetryRequest = true; error.config.headers.token= localStorage.getItem("accessToken"); return client(error.config); }); } }); /** * @description wrapper for making ajax requests * @param {object} object with method,url,data etc. */ const request = function(options) { const onSuccess = function(response) { return response.data; } const onError = function(error) { //console.error('Request Failed:', error.config); if (error.response) { //console.error('Status:', error.response.status); //console.error('Data:', error.response.data); //console.error('Headers:', error.response.headers); } else { console.error('Error Message:', error.message); } return Promise.reject(error.response || error.message); } return client(options) .then(onSuccess) .catch(onError); options } export default request;
[编辑]它的2019,这是相同的另一个实现。上面的解决方案很棒,但是不能用于多个失败的请求,反过来,它也会调用带有更新令牌的getToken。
import axios from "axios"; /* @internal */ import config from "../config"; import TokenService from "./token_service"; class Request { constructor() { this.baseURL = config.baseUrl; this.isRefreshing = false; this.failedRequests = []; this.tokenService = new TokenService(); this.client = axios.create({ baseURL: config.apiServerBaseUrl, headers: { clientSecret: this.clientSecret, }, }); this.beforeRequest = this.beforeRequest.bind(this); this.onRequestFailure = this.onRequestFailure.bind(this); this.processQueue = this.processQueue.bind(this); this.client.interceptors.request.use(this.beforeRequest); this.client.interceptors.response.use(this.onRequestSuccess, this.onRequestFailure); } beforeRequest(request) { const token = TokenService.getAccessToken(); request.headers.Authorization = `Token ${token}`; return request; } static onRequestSuccess(response) { return response.data; } async onRequestFailure(err) { const { response } = err; if (response.status === 401 && err && err.config && !err.config.__isRetryRequest) { if (this.isRefreshing) { try { const token = await new Promise((resolve, reject) => { this.failedRequests.push({ resolve, reject }); }); err.config.headers.Authorization = `Bearer ${token}`; return this.client(err.config); } catch (e) { return e; } } this.isRefreshing = true; err.config.__isRetryRequest = true; return new Promise((resolve, reject) => { this.tokenService.refreshAccessToken().then((token) => { this.tokenService.setAccessToken(token); err.config.headers.Authorization = `Bearer ${token}`; this.isRefreshing = false; this.processQueue(null, token); resolve(this.client(err.config)); }).catch((e) => { this.processQueue(e, null); reject(err.response); }); }); } throw response; } processQueue(error, token = null) { this.failedRequests.forEach((prom) => { if (error) { prom.reject(error); } else { prom.resolve(token); } }); this.failedRequests = []; } } const request = new Request(); export default request.client;