monorepo在H5项目中的应用(三、axios拦截器应用)

monorepo中AXIOS拦截器的应用

Axios作为promise封装的http库在我们日常开发中极为常见了,对于axios的二次封装这边就不过多赘述了,这里主要谈一下monorepo对于axios拦截器的应用。monorepo的特性就是通用与个性,不同的H5页面互相独立,但是往往又能互相复用许多东西,比如登录态、loading状态等等。这些就可以用Axios拦截器来做统一管理,但是每个H5项目总会遇到对自己个性的接口进行拦截处理,所以我们拦截器的模型设计也可以参照上一章的vuex的设计。
在这里插入图片描述

目录结构的调整

├── config             // vite相关配置
├── src                
|   ├── common         // 通用方法
|   |   ├── store           
|   |   ├── service       // 新增axios目录
|   |   |  ├── index.ts  // 通用拦截
|   |   |  ├── type.ts 
|   ├── packages       // 包文件
|   |   ├── demo1
|   |   |   ├── api  
|   |   |   |  ├── index.ts // 接口
|   |   |   |  ├── service.ts // 独有拦截  
|   |   |   ├── index.html
|   |   |   ├── main.ts
|   |   |   ├── config.json
|   |   |   ├── App.vue
|   |   |   ├── store
|   |   ├── demo2
|   |   |   ├── api  
|   |   |   |  ├── index.ts // 接口
|   |   |   |  ├── service.ts // 独有拦截  
|   |   |   ├── index.html
|   |   |   ├── main.ts
|   |   |   ├── App.vue
|   |   |   ├── store   
├── package.json
├── vite.config.ts

新增common目录下的service和每个demo目录下的service,分别用于管理通用拦截和实例独有拦截。

代码实现

通用service代码

// src/common/service/type.ts 
import { AxiosRequestConfig, AxiosResponse } from 'axios'
// 声明实例独有拦截器
export interface IServiceInterceptors {
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig | any
  requestInterceptorCatch?: (error: any) => any
  responseInterceptor?: (config: AxiosResponse) => AxiosResponse | any
  responseInterceptorCatch?: (error: any) => any
}

export interface IServiceConfig extends AxiosRequestConfig {
  interceptors?: IServiceInterceptors
  options?: IOptions
}

interface IOptions {
  showLoading?: boolean
}
// src/common/service/index.ts 
import axios, { AxiosInstance } from 'axios'
import { IServiceConfig, IServiceInterceptors } from './type'
import $store from '@store'

let needLoadingRequestCount = 0

// 结合vuex控制loading
const showLoading = config => {
  if (config.options) {
    const { showLoading = false } = config.options
    if (showLoading) {
      needLoadingRequestCount++
    }
  }
  if (needLoadingRequestCount === 1) {
    console.log('开启loading')
    $store.commit('commonModule/showLoading', isLoadingPartial)
  }
}

const hideLoading = config => {
  if (config.options) {
    const { showLoading = false } = config.options
    if (showLoading) {
      needLoadingRequestCount--
    }
  }
  if (needLoadingRequestCount <= 0) {
    console.log('关闭loading')
    $store.commit('commonModule/hideLoading')
  }
}

class CommonService {
  instance: AxiosInstance
  interceptors?: IServiceInterceptors
  constructor(config: IServiceConfig) {
    this.instance = axios.create(config)
    this.interceptors = config.interceptors
    
    // 实例独有的请求拦截
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch
    )
    // 实例独有的响应拦截
    this.instance.interceptors.response.use(
      this.interceptors?.responseInterceptor,
      this.interceptors?.responseInterceptorCatch
    )

    // 通用拦截器 实现loading开启关闭 取消重复请求
    this.instance.interceptors.request.use(
      config => {
        showLoading(config)
        return config
      },
      error => {
        return Promise.reject(error)
      }
    )

    // 响应拦截器
    this.instance.interceptors.response.use(
      (res: any) => {
        hideLoading(res.config)
        return res.data
      },
      error => {
        hideLoading(error.config || error)
        return Promise.reject(error)
      }
    )
  }
  // 简单封装一下get方法
    get<T = any>(config: IServiceConfig): Promise<T> {
    return this.instance.request({
      ...config,
      params: config.params || config.data,
      data: undefined,
      method: 'GET'
    })
  }
  request<T = any>(config: IServiceConfig): Promise<T> {
    return this.instance.request(config)
  }
}
export { CommonService }

通用的service暴露了一个通用的service类,里面实现了通用的拦截器,再由各个demo去实现该类,即可实现共用通用拦截,独享自己拦截的功能。

// src/packages/demo1/api/service.ts 
import { CommonService } from '@service'

const service = new CommonService({
  interceptors: {
    requestInterceptor: config => {
      console.log('实例请求拦截成功')
      return config
    },
    requestInterceptorCatch: err => {
      console.log('实例请求拦截失败')
      return Promise.reject(err)
    },
    responseInterceptor: res => {
      console.log('实例响应拦截成功')
      return res
    },
    responseInterceptorCatch: err => {
      console.log('实例响应拦截失败')
      return Promise.reject(err)
    }
  }
})
export default service
// src/packages/demo1/api/index.ts 
import service from './service'
enum URL {
  test = 'xxx'
}
interface GetTestData {
  id: string
}
const getTest = async (data: GetTestData) => {
 return await service.get({
    url: URL.test,
    data,
    options: { showLoading: true }
  })
}
export { getTest }

在项目中使用

import { getTest } from '../api'
onMounted(async () => {
    const res = await getTest({ id: '123' })
    console.log('res:', res)
})

运行结果:在这里插入图片描述
待改进点:独立拦截目前每种类型只给了一个对象,在实例实现的时候每种拦截器只能传入一个方法,不太利于拓展,可以通过一个拦截器数组来封装多个拦截器,这个项目已经实现了,这里就不过多赘述了。当然axios的封装也可以打磨一下,这里为了演示功能只做了一个简单的封装。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值