import cache from '@/plugins/cache'
|
import axiosInstance from './index'
|
import Vue from 'vue'
|
import TwoFAWindow from '@/components/common/TwoFAWindow'
|
const requestMethods = ['get', 'post', 'delete', 'put', 'head', 'options', 'patch', 'request']
|
const extendsMethods = {}
|
|
/**
|
* 模拟Promise,达到Promise的then,catch和finally可以重复执行
|
*
|
* @param fn 回调
|
*/
|
const RepeatablePromise = function (fn) {
|
this.__then = []
|
this.__catch = null
|
this.__finally = null
|
this.then = function (thenFn) {
|
this.__then.push(thenFn)
|
return this
|
}
|
this.catch = function (catchFn) {
|
this.__catch = catchFn
|
return this
|
}
|
this.finally = function (finallyFn) {
|
this.__finally = finallyFn
|
return this
|
}
|
fn(data => {
|
try {
|
let returnData = null
|
for (let i = 0; i < this.__then.length; i++) {
|
if (i === 0) {
|
returnData = this.__then[i](data)
|
} else {
|
returnData = this.__then[i](returnData)
|
}
|
}
|
} catch (e) {
|
if (this.__catch) {
|
throw new Error('Eva: ')
|
}
|
this.__catch && this.__catch(e)
|
}
|
this.__finally && this.__finally()
|
}, e => {
|
this.__catch && this.__catch(e)
|
this.__finally && this.__finally()
|
})
|
}
|
|
/**
|
* 构建基础请求对象Promise代理对象
|
*
|
* @param method 请求方式
|
* @param args 请求参数
|
* @returns {{__access(*, *=): *, finally(): *, then(): *, catch(): *, __result_promise: null, __arguments: *}|*}
|
*/
|
const buildBasePromiseProxy = (method, args) => {
|
return {
|
// post,get等请求方法的调用参数
|
__arguments: args,
|
// 请求结果的promise对象
|
__result_promise: null,
|
// 代理then方法,直接调用目标promise的then方法
|
then () {
|
return this.__access('then', arguments)
|
},
|
// 代理catch方法,直接调用目标promise的catch方法
|
catch () {
|
return this.__access('catch', arguments)
|
},
|
// 代理finally方法,直接调用目标promise的finally方法
|
finally () {
|
return this.__access('finally', arguments)
|
},
|
__access (methodName, args) {
|
if (this.__result_promise != null) {
|
return this.__result_promise[methodName].apply(this.__result_promise, args)
|
}
|
// 开启了2FA认证
|
if (this.__with_2fa) {
|
if (this.__2fa_window != null) {
|
this.__result_promise = new RepeatablePromise((resolve, reject) => {
|
this.__2fa_window.$on('then', resolve)
|
this.__2fa_window.$on('catch', reject)
|
this.__2fa_window.$on('cancel', reject)
|
})
|
// - 打开窗口,在此处打开窗口,意味着必须执行then,catch或finally才会打开2fa认证窗口
|
this.__2fa_window.open(axiosInstance, method, this.__arguments)
|
}
|
}
|
// 未开启2fa的情况下,直接发送请求
|
if (this.__result_promise == null) {
|
this.__result_promise = axiosInstance[method].apply(axiosInstance, this.__arguments)
|
}
|
// 如果开启了缓存,则在请求成功后写入缓存
|
if (this.__with_cache) {
|
this.__result_promise.then(data => {
|
this.__cache_impl.set(this.__cache_key, data)
|
return data
|
})
|
}
|
return this.__result_promise[methodName].apply(this.__result_promise, args)
|
}
|
}
|
}
|
|
/**
|
* 构建缓存请求对象Promise代理对象
|
*
|
* @param cacheKey 缓存key
|
* @param method 请求方式
|
* @param args 请求参数
|
* @param cacheImplName 缓存实现名称
|
* @returns {{cache(): *, __with_cache: boolean, __cache_key: *, __cache_impl: *}|Promise<any>|buildCachePromiseProxy}
|
*/
|
const buildCachePromiseProxy = (cacheKey, method, args, cacheImplName) => {
|
return {
|
// 缓存标记
|
__with_cache: true,
|
// 缓存key
|
__cache_key: cacheKey,
|
// 缓存实现
|
__cache_impl: cache[cacheImplName],
|
// 从缓存中获取数据
|
cache () {
|
// 从缓存中获取数据
|
const data = this.__cache_impl.get(cacheKey)
|
// 如果从缓存中获取到了数据,则直接构造一个成功的promise
|
if (data != null) {
|
this.__result_promise = Promise.resolve(data)
|
}
|
// 如果已经获取到了数据,则由以上成功的promise来接手then和catch的处理
|
if (this.__result_promise != null) {
|
return this.__result_promise
|
}
|
return this
|
}
|
}
|
}
|
|
/**
|
* 构建2FA请求对象Promise代理对象
|
*
|
* @param twoFAWindow 2FA认证窗口实例
|
* @returns {{__2fa_window: *, __with_2fa: boolean}}
|
*/
|
const build2FAPromiseProxy = twoFAWindow => {
|
return {
|
// 2fa标记
|
__with_2fa: true,
|
// 2fa窗口对象
|
__2fa_window: twoFAWindow
|
}
|
}
|
|
/**
|
* 扩展方法:开启缓存
|
*
|
* @param cacheKey 缓存的key
|
* @param isLocal 是否缓存到本地缓存LocalStorage,为false时缓存到SessionStorage
|
* @usage:request.cache('test').[post(), get()...]
|
* @returns {{isExtendsAxiosInstance: boolean, post: Function, get: Function, ...}}
|
*/
|
extendsMethods.cache = function (cacheKey, isLocal = false) {
|
if (cacheKey == null) {
|
throw Error('Request cache key can not be null.')
|
}
|
let cacheAxiosInstance = {
|
// 标记为axios扩展实例,用于与原生axios作区分
|
isExtendsAxiosInstance: true
|
}
|
if (this.isExtendsAxiosInstance) {
|
cacheAxiosInstance = this
|
}
|
for (const method of requestMethods) {
|
if (cacheAxiosInstance[method] == null) {
|
cacheAxiosInstance[method] = function () {
|
return {
|
...buildBasePromiseProxy(method, arguments),
|
...buildCachePromiseProxy(cacheKey, method, arguments, isLocal ? 'local' : 'session')
|
}
|
}
|
continue
|
}
|
// 不为null时说明在调用cache前调用了其他扩展方法,此时诸如post,get方法的返回值做合并,防止扩展方法丢失。
|
const originMethod = cacheAxiosInstance[method]
|
cacheAxiosInstance[method] = function () {
|
const request = originMethod()
|
Object.assign(request, {
|
...buildBasePromiseProxy(method, arguments),
|
...buildCachePromiseProxy(cacheKey, method, arguments, isLocal ? 'local' : 'session')
|
})
|
return request
|
}
|
}
|
// 添加扩展方法
|
for (const key in extendsMethods) {
|
cacheAxiosInstance[key] = extendsMethods[key]
|
}
|
return cacheAxiosInstance
|
}
|
|
/**
|
* 扩展方法:开启2FA认证
|
*
|
* @usage:request.twoFA().[post(), get()...]
|
* @returns {{isExtendsAxiosInstance: boolean, post: Function, get: Function, ...}}
|
*/
|
extendsMethods.twoFA = function (props) {
|
// 打开2FA窗口
|
let $twoFAWindow = null
|
// - 只有在为获取到密码时(未保存密码或密码已过期)时才打开2FA窗口
|
if (cache.twoFA.getPassword() == null) {
|
const TwoFAWindowVue = Vue.extend(TwoFAWindow)
|
$twoFAWindow = new TwoFAWindowVue({
|
el: document.createElement('div'),
|
propsData: props
|
})
|
document.body.appendChild($twoFAWindow.$el)
|
}
|
let twofaAxiosInstance = {
|
// 标记为axios扩展实例,用于与原生axios作区分
|
isExtendsAxiosInstance: true
|
}
|
if (this.isExtendsAxiosInstance) {
|
twofaAxiosInstance = this
|
}
|
for (const method of requestMethods) {
|
if (twofaAxiosInstance[method] == null) {
|
twofaAxiosInstance[method] = function () {
|
return {
|
...buildBasePromiseProxy(method, arguments),
|
...build2FAPromiseProxy($twoFAWindow)
|
}
|
}
|
continue
|
}
|
// 不为null时说明在调用twoFA前调用了其他扩展方法,此时诸如post,get方法的返回值做合并,防止扩展方法丢失。
|
const originMethod = twofaAxiosInstance[method]
|
twofaAxiosInstance[method] = function () {
|
const request = originMethod()
|
Object.assign(request, {
|
...buildBasePromiseProxy(method, arguments),
|
...build2FAPromiseProxy($twoFAWindow)
|
})
|
return request
|
}
|
}
|
// 添加扩展方法
|
for (const key in extendsMethods) {
|
twofaAxiosInstance[key] = extendsMethods[key]
|
}
|
return twofaAxiosInstance
|
}
|
|
export default extendsMethods
|