目錄結構:
http-helper.ts
import axios, {CancelTokenSource, AxiosResponse, AxiosRequestConfig, AxiosError} from 'axios';
import Storage from './storage-helper';
import CryptoHelper from './cryptoJs-helper';
const CANCELTTYPE = {
CACHE: 1,
REPEAT: 2,
};
interface ICancel {
data: any;
type: number;
}
interface Request {
md5Key: string;
source: CancelTokenSource;
}
const pendingRequests: Request[] = [];
const http = axios.create();
const storage = new Storage();
const cryptoHelper = new CryptoHelper('cacheKey');
http.interceptors.request.use((config: AxiosRequestConfig) => {
/**
* 為每一次請求生成一個cancleToken
*/
const source = axios.CancelToken.source();
config.cancelToken = source.token;
/**
* 緩存命中判斷
* 成功則取消當次請求
*/
const data = storage.get(cryptoHelper.encrypt(
config.url + JSON.stringify(config.data) + (config.method || ''),
));
if (data && (Date.now() <= data.exppries)) {
console.log(`接口:${config.url} 緩存命中 -- ${Date.now()} -- ${data.exppries}`);
source.cancel(JSON.stringify({
type: CANCELTTYPE.CACHE,
data: data.data,
}));
}
/**
* 重復請求判斷
* 同url,同請求類型判定為重復請求
* 以最新的請求為准
*/
const md5Key = cryptoHelper.encrypt(config.url + (config.method || ''));
/**
* 將之前的重復且未完成的請求全部取消
*/
const hits = pendingRequests.filter((item) => item.md5Key === md5Key);
if (hits.length > 0) {
hits.forEach((item) => item.source.cancel(JSON.stringify({
type: CANCELTTYPE.REPEAT,
data: '重復請求,以取消',
})));
}
/**
* 將當前請求添加進請求對列中
*/
pendingRequests.push({
md5Key,
source,
});
return config;
});
http.interceptors.response.use((res: AxiosResponse) => {
/**
* 不論請求是否成功,
* 將本次完成的請求從請求隊列中移除
*/
// 以同樣的加密方式(MD5)獲取加密字符串
const md5Key = cryptoHelper.encrypt(res.config.url + (res.config.method || ''));
const index = pendingRequests.findIndex((item) => item.md5Key === md5Key);
if (index > -1) {
pendingRequests.splice(index, 1);
}
if (res.data && res.data.type === 0) {
if (res.config.data) {
const dataParse = JSON.parse(res.config.data);
if (dataParse.cache) {
if (!dataParse.cacheTime) {
dataParse.cacheTime = 1000 * 60 * 3;
}
storage.set(cryptoHelper.encrypt(res.config.url + res.config.data + (res.config.method || '')), {
data: res.data.data,
exppries: Date.now() + dataParse.cacheTime,
});
console.log(`接口:${res.config.url} 設置緩存,緩存時間: ${dataParse.cacheTime}`);
}
}
return res.data.data;
} else {
return Promise.reject('接口報錯了!');
}
});
/**
* 封裝 get、post 請求
* 集成接口緩存過期機制
* 緩存過期將重新請求獲取最新數據,並更新緩存
* 數據存儲在localstorage
* {
* cache: true
* cacheTime: 1000 * 60 * 3 -- 默認緩存3分鍾
* }
*/
const httpHelper = {
get(url: string, params: any) {
return new Promise((resolve, reject) => {
http.get(url, params).then(async (res: AxiosResponse) => {
resolve(res);
}).catch((error: AxiosError) => {
if (axios.isCancel(error)) {
const cancle: ICancel = JSON.parse(error.message);
if (cancle.type === CANCELTTYPE.REPEAT) {
return resolve([]);
} else {
return resolve(cancle.data);
}
} else {
return reject(error);
}
});
});
},
post(url: string, params: any) {
return new Promise((resolve, reject) => {
http.post(url, params).then(async (res: AxiosResponse) => {
resolve(res);
}).catch((error: AxiosError) => {
if (axios.isCancel(error)) {
const cancle: ICancel = JSON.parse(error.message);
if (cancle.type === CANCELTTYPE.REPEAT) {
return resolve(null);
} else {
return resolve(cancle.data);
}
} else {
return reject(error);
}
});
});
},
};
export default httpHelper;
cryptoJs-helper.ts 封裝生成加密串
import cryptoJs from 'crypto-js';
class CryptoHelper {
public key: string;
constructor(key: string) {
/**
* 如需秘鑰,可以在實例化時傳入
*/
this.key = key;
}
/**
* 加密
* @param word
*/
public encrypt(word: string | undefined): string {
if (!word) {
return '';
}
const encrypted = cryptoJs.MD5(word);
return encrypted.toString();
}
}
export default CryptoHelper;
storage-helper.ts 封裝數據存儲
class Storage {
public get(key: string | undefined) {
if (!key) { return; }
const text = localStorage.getItem(key);
try {
if (text) {
return JSON.parse(text);
} else {
localStorage.removeItem(key);
return null;
}
} catch {
localStorage.removeItem(key);
return null;
}
}
public set(key: string | undefined, data: any) {
if (!key) {
return;
}
localStorage.setItem(key, JSON.stringify(data));
}
public remove(key: string | undefined) {
if (!key) {
return;
}
localStorage.removeItem(key);
}
}
export default Storage;