import axios from 'axios' import { Loading, Message, MessageBox, Notification } from 'element-ui' import store from '@/store' import { getToken } from '@/utils/auth' import errorCode from '@/utils/errorCode' import { blobValidate, tansParams } from '@/utils/bonus' import cache from '@/plugins/cache' import { saveAs } from 'file-saver' import { decryptCBC, encryptCBC } from '@/utils/aescbc' import { hashWithSM3AndSalt } from '@/utils/sm' // 导入SM3哈希函数 let downloadLoadingInstance export let isRelogin = { show: false } axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' // 创建axios实例 const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 }) // 请求拦截器 service.interceptors.request.use( (config) => { const isToken = (config.headers || {}).isToken === false const isRepeatSubmit = (config.headers || {}).repeatSubmit === false // 如果需要token且存在token,则设置Authorization头 if (getToken() && !isToken) { config.headers['Authorization'] = 'Bearer ' + getToken() } // 处理GET请求参数并加密 if (config.params) { let param = tansParams(config.params) if (param) { param = param.slice(0, -1) param = encryptCBC(param) config.headers['Params-Hash'] = hashWithSM3AndSalt(param) } config.url = `${config.url}?${param}` config.params = {} } // 防止重复提交 if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { const requestObj = { url: config.url, data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, time: new Date().getTime() } const requestSize = Object.keys(JSON.stringify(requestObj)).length const limitSize = 5 * 1024 * 1024 // 限制请求数据大小为5M if (requestSize >= limitSize) { console.warn(`[${config.url}]: 请求数据大小超出允许的5M限制,无法进行防重复提交验证。`) return config } const sessionObj = cache.session.getJSON('sessionObj') if (!sessionObj) { cache.session.setJSON('sessionObj', requestObj) } else { const { url, data, time } = sessionObj const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交 if (data === requestObj.data && requestObj.time - time < interval && url === requestObj.url) { const message = '数据正在处理,请勿重复提交' console.warn(`[${url}]: ${message}`) return Promise.reject(new Error(message)) } else { cache.session.setJSON('sessionObj', requestObj) } } } // 如果Content-Type为application/json且数据为对象,则加密数据 if (config.headers['Content-Type'] === 'application/json;charset=utf-8' && typeof config.data === 'object') { config.data = encryptCBC(JSON.stringify(config.data)) config.headers['Content-Type'] = 'application/json' console.log(config.data) config.headers['Params-Hash'] = hashWithSM3AndSalt(config.data) // 添加数据哈希到请求头 } // 对下载请求进行数据参数拦截加密 if (config.headers['Content-Type'] === 'application/x-www-form-urlencoded') { if (typeof config.data === 'object') { let formData = tansParams(config.data) if (formData) { formData = formData.slice(0, -1) config.data = encryptCBC(formData) console.log(config.data) config.headers['Params-Hash'] = hashWithSM3AndSalt(config.data) // 添加参数哈希到请求头 } } else { config.data = encryptCBC('formData=' + JSON.stringify(config.data)) config.headers['Params-Hash'] = hashWithSM3AndSalt(config.data) // 添加参数哈希到请求头 } } // 如果Content-Type为空,则设置为application/json if (!config.headers['Content-Type']) { config.headers['Content-Type'] = 'application/json' console.warn('请求类型为空') } return config }, (error) => { console.log(error) return Promise.reject(error) } ) // 响应拦截器 service.interceptors.response.use( (res) => { // 自动解密响应数据 if (res.data.decrypt) { res.data = JSON.parse(decryptCBC(res.data.data)) } else if (typeof res.data.code === 'undefined') { res.data = res.data.data } // 获取状态码 const code = res.data.code || 200 const msg = errorCode[code] || res.data.msg || errorCode['default'] // 处理二进制数据直接返回 if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { return res.data } if (code === 401) { if (!isRelogin.show) { isRelogin.show = true MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { isRelogin.show = false store.dispatch('LogOut').then(() => { location.href = '/index' }) }).catch(() => { isRelogin.show = false }) } return Promise.reject('无效的会话,或者会话已过期,请重新登录。') } else if (code === 500) { Message({ message: msg, type: 'error' }) return Promise.reject(new Error(msg)) } else if (code === 601) { Message({ message: msg, type: 'warning' }) return Promise.reject('error') } else if (code !== 200) { Notification.error({ title: msg }) return Promise.reject('error') } else { return res.data } }, (error) => { console.log('err' + error) let { message } = error if (message === 'Network Error') { message = '后端接口连接异常' } else if (message.includes('timeout')) { message = '系统接口请求超时' } else if (message.includes('Request failed with status code')) { message = `系统接口${message.substr(message.length - 3)}异常` } Message({ message, type: 'error', duration: 5 * 1000 }) return Promise.reject(error) } ) // 通用下载方法 export function download(url, params, filename, config) { downloadLoadingInstance = Loading.service({ text: '正在下载数据,请稍候', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }) console.log(params) return service.post(url, params, { transformRequest: [(params) => params], headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Params-Hash': hashWithSM3AndSalt(params) }, responseType: 'blob', ...config }).then(async(data) => { const isBlob = blobValidate(data) if (isBlob) { const blob = new Blob([data]) saveAs(blob, filename) } else { const resText = await data.text() const rspObj = JSON.parse(resText) const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] Message.error(errMsg) } downloadLoadingInstance.close() }).catch((r) => { console.error(r) Message.error('下载文件出现错误,请联系管理员!') downloadLoadingInstance.close() }) } export default service