import axios from 'axios' import apiConfig from './baseurl' import store from '@/store' // 导入 Vuex store import CryptoJS from 'crypto-js'; import { Message } from 'element-ui' const service = axios.create({ baseURL: apiConfig.baseURL, withCredentials: false, // 当跨域请求时发送cookie timeout: 60000, // request timeout }) // 对 POST 请求参数进行排序 const sortPostParams = (params) => { const keys = Object.keys(params); keys.sort((a, b) => { for (let i = 0; i < Math.min(a.length, b.length); i++) { const asciiA = a.charCodeAt(i); const asciiB = b.charCodeAt(i); if (asciiA !== asciiB) { return asciiA - asciiB; } } // 如果两个字符串长度不同,则较短的字符串排在前面 return a.length - b.length; }); const sortedParams = {}; keys.forEach(key => { sortedParams[key] = params[key]; }); return sortedParams; } //去除对象中空值的属性 const removeEmptyProperties = (obj) => { return Object.fromEntries(Object.entries(obj).filter(([key, value]) => value !== undefined && value !== null && value !== '' && (Array.isArray(value) ? value.length > 0 : true))); }; // 将对象转换为字符串用&拼接 const objToString = (obj) => { // 使用 Object.keys() 获取对象的 key 数组 const keys = Object.keys(obj); // 使用 Array.prototype.map() 将每个 key-value 对转化为字符串 const strArray = keys.map(key => { const value = obj[key]; if (Array.isArray(value) || typeof value === 'object' && value !== null) { return ''; } else { return `${key}=${value}`; } }); // 使用 Array.prototype.filter() 过滤掉空字符串 const filteredStrArray = strArray.filter(str => str !== ''); // 使用 Array.prototype.join() 将字符串数组拼接成一个字符串 const str = filteredStrArray.join('&'); return str; } // 生成随机字符串 const generateRandomString = (length) => { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const str = []; for (let i = 0; i < length; i++) { const randomIndex = Math.floor(Math.random() * chars.length); str.push(chars[randomIndex]); } return str.join(''); } // 对字符串进行 HMAC-SHA1 加密 const encryptWithHMACSHA1 = (message, secret) => { return CryptoJS.HmacSHA1(message, secret).toString(CryptoJS.enc.Base64); }; // 请求拦截 service.interceptors.request.use( config => { const o = config let { data, method } = o const Authorization = localStorage.getItem('token') || '' if (method == 'post') { let copyData = JSON.parse(JSON.stringify(data)) // 对 POST 请求参数进行处理 let sortData = sortPostParams(copyData) sortData = removeEmptyProperties(sortData) // 将处理后的 POST 请求参数转换为字符串 let strData = objToString(sortData) // 生成随机字符串 用作加密秘钥 let nonce_str = generateRandomString(16) // 对字符串进行 HMAC-SHA1 加密 并转化为 Base64 let sign = encryptWithHMACSHA1(strData, nonce_str) o.headers = { ...o.headers, timestamp: new Date().getTime(), sign, nonce_str, Authorization, client: localStorage.getItem('client') } } else { o.headers = { timestamp: new Date().getTime(), ...config.headers, Authorization, client: localStorage.getItem('client') } } return { ...o }; }, error => { return Promise.reject(error) } ) // 响应拦截 service.interceptors.response.use( response => { if (!response) { return } const res = response; if (res.data.code == 200) { if (!res.data.data) { return Promise.resolve({}) } return Promise.resolve(res.data.data) } else { if (res.data.code == 103 || res.data.code == 401) { Message({ message: res.data.msg || '登录已过期,请重新登录', type: 'warning', duration: 2000 }) store.commit('clearToken') window.location.replace(`/`); return Promise.reject(res.data.data) } Message({ message: res.data.msg || '服务器错误', type: 'error', duration: 4000 }) return Promise.reject(res.data.data) } }, error => { Message({ message: error.message, type: 'error', duration: 5000 }) return Promise.reject(error) } ) export default service