import qs from 'qs' import VerifyPoints from './verify-popup' const verify = new VerifyPoints() const JSONOrFormData = config => { let type = '' const contentType = config.headers['Content-Type'] // json --- application/json;charset=utf-8 // formData --- application/x-www-form-urlencoded const contentTypeMap = { json: 'application/json', formData: 'application/x-www-form-urlencoded' } if (!contentType) return 'json' for (const key in contentTypeMap) { const matching = contentType.includes(contentTypeMap[key]) if (matching) { type = key break } } return type } // 缓存原有拦截器 let cacheResponseInterceptors = [] // 缓存所有拦截器,并清除实例上所有拦截器, function clearAllResponseInterceptors (service) { // https://github.com/axios/axios/blob/v1.x/lib/core/InterceptorManager.js // 移除所有拦截器,github中的这个clear函数后来被移除了 const handlers = service.interceptors.response.handlers if (Array.isArray(handlers) && handlers.length > 0) { for (let i = 0; i < handlers.length; i++) { cacheResponseInterceptors.push(handlers[i]) } service.interceptors.response.handlers = [] } } // 从缓存恢复拦截器 function restoreResponseInterceptors (service) { if (Array.isArray(cacheResponseInterceptors) && cacheResponseInterceptors.length > 0) { service.interceptors.response.handlers = cacheResponseInterceptors // 恢复完成后及时清除缓存数组 cacheResponseInterceptors = [] } } // 清除所有拦截器,并注册当前拦截器 // 移除拦截器后必须在某处恢复,否则会影响其他请求 function clearOtherResponseInterceptors (service) { clearAllResponseInterceptors(service) registerInterceptors(service) } function closeVerify () { if (verify.show) { verify.verify({ value: false }) } } export default function registerInterceptors (service) { // 注册响应拦截器 service.interceptors.response.use(async (response) => { const res = response.data const config = response.config // 如果请求不是200,有可能是403(被拉黑了),就直接跳过本次拦截 if (response.status !== 200) { // 如果全局验证码显示,并且返回结果正常。则关闭验证码 closeVerify() return response } // 验证码验证成功 if (res.antiVerify === 1) { /** * 思路1(正在使用):移除其他响应拦截器,获取到response并返回后,在恢复拦截器 * 优点:能够完全还原新请求的信息(包含响应头等,兼容验证请求响应头和正常请求响应头不同的情况) * 缺点:实现稍微复杂 * * 思路2:仅替换response中请求返回的数据。不操作任何拦截器,await service(conf)后,直接替换response中的data即可 * 优点:实现简单 * 缺点:不能实现<思路1>中完全复现响应头的情况 */ // 移除其他响应拦截器 clearOtherResponseInterceptors(service) let r = response try { r = await service(config) // 恢复响应拦截 restoreResponseInterceptors(service) } catch (error) { // 恢复响应拦截 restoreResponseInterceptors(service) console.error(error) } finally { closeVerify() } return r } else { restoreResponseInterceptors(service) } // 需要验证 if (res.antiVerify === -1 && res.textVerify) { // 等待验证码操作完成 const iReceivedMsg = await new Promise((resolve) => { verify.verify({ value: true, imgBase64: res.imgData, textVerify: res.textVerify, refresh () { resolve({ type: 'refresh' }) }, confirm (msg) { resolve({ type: 'confirm', imgw: msg.imgWidth, antiVerifyCheck: msg.pointsCoordinate.join(';') }) } }) }) // 如果确定事件触发 if (iReceivedMsg && iReceivedMsg.type === 'confirm') { // GET请求在data中添加数据, POST请求在params中添加数据 const requestType = config.method.toUpperCase() switch (requestType) { case 'GET': { if (config.params) { config.params.imgw = iReceivedMsg.imgw config.params.antiVerifyCheck = iReceivedMsg.antiVerifyCheck } else { config.params = iReceivedMsg } break } case 'POST': { // 判断json还是formData const sendVerify = { imgw: iReceivedMsg.imgw, antiVerifyCheck: iReceivedMsg.antiVerifyCheck } const sendType = JSONOrFormData(config) if (sendType === 'formData') { if (config.data) { // 先把字符串转为对象,赋值后在转回字符串 const cacheMsg = qs.parse(config.data) config.data = qs.stringify({ ...cacheMsg, ...sendVerify }) } else { config.data = qs.stringify(sendVerify) } } else if (sendType === 'json') { if (config.data) { // 先把字符串转为对象,赋值后在转回字符串 config.data = JSON.parse(config.data) Object.assign(config.data, sendVerify) config.data = JSON.stringify(config.data) } else { config.data = JSON.stringify(sendVerify) } } break } default: { console.log('非常规请求,请单独配置拦截请求内容,并写入参数 --- 来自: @jianyu/vue-anti') break } } } // 重发请求以验证《验证码》是否正确 // 此时不需要当前拦截器以外的拦截器 // 移除其他响应拦截器,在请求时恢复 clearOtherResponseInterceptors(service) return service(config) } else { return response } }, error => { return error }) }