支持区分env
这样配置有个好处。有时候我们新增的接口想走本地mock,比如后端还未实现,已有的接口走线上数据,这样以配置,就简单明了多了
baseMap: { prod: 'https://wwww.baidu.com', test: 'https://wwww.baidu.com', local: 'http://127.0.0.1:4320', baseURL: 'https://localhost:8080' },
export default { getBaseInfo: { method: 'get', url: '/base/get', env:'local' }, getBaseRestInfo: { method: 'get', url: '/base/get/:id/kill/:test', env:'test' } }
支持restful风格
export default { getBaseInfo: { method: 'get', url: '/base/get', env:'local' }, getBaseRestInfo: { method: 'get', url: '/base/get/:id/qs/:test', env:'test' } }
实现
:
/** * 替换restful请求中的url */ restful(url: string, rest: Rest): string { /** * [xyz]一个字符集合。匹配方括号中的任意字符 * 比如正则表达式是[abcd]==>匹配brisket"中的‘b’ */ const regex = /\:[^/]*/g /** * 一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。参考下面的指定一个函数作为参数。 * 另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。 * 匹配模式是这样的\:[^/]* 为一个整体 全局g下多次匹配 也就是多次调用fn * [^/]匹配得到的是一个字符 只要匹配的url出现的一个字符在 [^/]中出现就匹配成功 但是是单个的 所以要多次匹配 */ return url.replace(regex, p => { console.log(p) /** * :id ===>返回id */ const key = p.slice(1) if (rest[key]) { return rest[key] } return p }) }
支持取消请求
从
v0.22.0
开始,Axios 支持以 fetch API 方式——AbortController
取消请求:
// 1. 支持取消请求 const cancelMap: { [key: string]: any } = {} Apis.reqMiddleware.push({ onFulfilled: (config) => { const source = axios.CancelToken.source() config.cancelToken = source.token cancelMap[config.url!] = source return config } }) createInstance.cancel = function(url: string) { if (cancelMap[url]) { cancelMap[url].cancel('Request was cancelled') delete cancelMap[url] } }
支持重新请求
function createInstance( serverMap: ServerMap, apiMap: ApisMap, common?: AxiosRequestConfig ): ApisInstance { Apis.resMiddleware.push({ onFulfilled: void 0, onRejected: function axiosRetryInterceptor(err) { const config = err.config /** * 如果没有retry配置那么就不走这个拦截器 * 因为发生错误,我们还在这个拦截器中 request2 interceptor --> request1 interceptor-->dispatchRequest--> response1 interceptor--> response2 interceptor * 这时候在拦截器中重新发起请求把得到的响应结果发给最后的Promise * 最后的Promise注册中我们成功和失败的业务 * 这样可以避免:其他的那个几十个.vue页面的 this.$axios的get 和post 的方法根本就不需要去修改它们的代码。 */ if (!config || !config.retry) return Promise.reject(err) /** * 已经尝试retry的次数 */ config.__retryCount = config.__retryCount || 0 if (config.__retryCount >= config.retry) { return Promise.reject(err) } config.__retryCount += 1 /** * 等待多少秒后才进行retry */ const backoff = new Promise(function(resolve) { setTimeout(function() { resolve() }, config.retryDelay || 1) }) return backoff.then(function() { /** * 返回结果 * 是个Promise对象 * 不reject 返回的数据被成功的回调拿到 */ return axios(config) }) } }) const apis = new Apis(serverMap, apiMap, common) /** * new过后清空以前的拦截器队列 * 因为new完一个实例过后,拦截器信息可以作废 * 所以要确保你实例化之前先注册拦截器 */ Apis.reqMiddleware = [] Apis.resMiddleware = [] return apis.instance }
支持缓存
// 3. 支持接口缓存 const cacheMap: { [key: string]: any } = {} Apis.resMiddleware.push({ onFulfilled: (response) => { cacheMap[response.config.url!] = response return response } }) Apis.reqMiddleware.push({ onFulfilled: (config) => { if (cacheMap[config.url!]) { throw new axios.Cancel('Request was cached') } return config } })
支持限流
// 2. 支持接口限流 const LIMIT = 5 // 例如,5个请求每秒 const INTERVAL = 1000 // 1秒 let tokens = LIMIT setInterval(() => { tokens = LIMIT }, INTERVAL) Apis.reqMiddleware.push({ onFulfilled: (config) => { if (tokens > 0) { tokens-- return config } else { throw new Error('Rate limit exceeded') } } })
总结
上述的apis是我实际项目中封装的,当然文章给的大部分是伪代码,但是思路是对的,大家可以按照这个思路封装自己项目中的请求库,然后发布成npm包