ts+axios封装

这篇文章封装的axios已经满足如下功能:

  • 无处不在的代码提示;
  • 灵活的拦截器;
  • 可以创建多个实例,灵活根据项目进行调整;
  • 每个实例,或者说每个接口都可以灵活配置请求头、超时时间等;


一 基础封装

//目录:src/service/request/index.ts

import axios from "axios";
import type{ AxiosInstance, AxiosRequestConfig } from "axios"

class HYRequest {
  // 声明属性,并且我们希望instance类型与create出的类型一致(create里提供的,不用记)
  instance: AxiosInstance
  // 1.request实例 => axios实例
  // 创建出来的每个实例都对应一个axios实例
  constructor(config: AxiosRequestConfig) {
    // config: any
    // any类型不好,传入参数的类型不规范,所以改成AxiosRequestConfig类型(create里提供的,不用记)
    this.instance = axios.create(
    // 我们不希望baseURL,timeout写死,希望是别人传过来的,所以在创建实例的时候可以传过来config,在src/index.ts中创建实例
      // {
      // baseURL: "xxx",
      // timeout: 10000
      // }
    config
    )
  }
    // 2.封装网络请求的方法(主要封装request方法)
  request(config: AxiosRequestConfig) {
    return this.instance.request(config)
  }
}
export default HYRequest

image-20230403102900784

image-20230403103225900

二 拦截器封装

类拦截器

类拦截器只需要在类中对axios.create()创建的实例调用interceptors下的两个拦截器即可,代码如下:

//目录:src/request/index.ts
// 给每一个instance实例都添加拦截器
import axios from "axios"
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"
import type { HYRequestConfig } from "./type"

class HYRequest {
  instance: AxiosInstance

  // request实例 => axios的实例
  constructor(config: HYRequestConfig) {
    this.instance = axios.create(config)

    // 使用类拦截器
    // 每个instance实例都添加拦截器
    this.instance.interceptors.request.use(config => {
      // loading/token
      console.log("全局请求成功的拦截")
      return config
    }, err => {
      console.log("全局请求失败的拦截")
      return err
    })
    this.instance.interceptors.response.use(res => {
      console.log("全局响应成功的拦截")
      return res.data
    }, err => {
      console.log("全局响应失败的拦截")
      return err
    })
}
export default HYRequest

实例拦截器

实例拦截器是为了保证封装的灵活性,因为每一个实例中的拦截后处理的操作可能是不一样的,所以在定义实例时,允许我们传入拦截器。

  • 针对AxiosRequestConfig配置进行扩展,因为AxiosRequestConfig中不允许我们传入拦截器(interceptors),而hyRequest中又需要传入一interceptors,所以自定义一个HYRequestConfig,让其继承于AxiosRequestConfig,且允许传入拦截器,代码如下:
//目录:src/request/type.ts
import type { AxiosRequestConfig, AxiosResponse } from "axios"

interface HYInterceptors<T = AxiosResponse> {
  //请求拦截
  requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestFailureFn?: (err: any) => any
  //响应拦截
  responseSuccessFn?: (res: T) => T
  responseFailureFn?: (err: any) => any
}
//自定义传入的参数
export interface HYRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: HYInterceptors<T>
}
  • 使用类拦截器:代码如下:
//目录:src/request/index.ts
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"
import type { HYRequestConfig } from "./type"

// 针对AxiosRequestConfig配置进行扩展,因为AxiosRequestConfig中不允许我们传入拦截器(interceptors),而hyRequest中又需要传入一interceptors,所以自定义一个HYRequestConfig,让其继承于AxiosRequestConfig,且允许传入拦截器
// 在request/type.ts中封装了

class HYRequest {
  // 声明属性,并且我们希望instance类型与create出的类型一致(create里提供的,不用记)
  instance: AxiosInstance
  // 1.request实例 => axios实例
  // 创建出来的每个实例都对应一个axios实例
  constructor(config: HYRequestConfig) {
    // config: any
    // any类型不好,传入参数的类型不规范,所以改成AxiosRequestConfig类型(create里提供的,不用记)
    this.instance = axios.create(
    // 我们不希望baseURL,timeout写死,希望是别人传过来的,所以在创建实例的时候可以传过来config,在src/index.ts中创建实例
      // {
      // baseURL: "xxx",
      // timeout: 10000
      // }
    config)

      
    //使用类拦截器
    // 给每一个instance实例都添加拦截器
    this.instance.interceptors.request.use(config => {
      console.log("全局请求成功的拦截")
      return config
    }, err => {
      console.log("全局请求失败的拦截")
      return err
    })
    this.instance.interceptors.response.use(res => {
      console.log("全局响应成功拦截")
      return res.data
    }, err => {
      console.log("全局响应失败拦截")
      return err
    })

    //使用实例拦截器
    // 针对特定的hyRequest实例,比如hyRequest2,添加拦截器,
    //hyRequest2详见创建实例的目录:src/service/index.ts
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    )
      this.instance.interceptors.response.use(
        config.interceptors?.responseSuccessFn,
        config.interceptors?.responseFailureFn
      )
  }

  // 2.封装网络请求的方法(主要封装request方法)
  request(config: AxiosRequestConfig) {
    return this.instance.request(config)
  }
}

export default HYRequest

接口拦截器

对单一接口进行拦截,例如同一个实例的不同接口有不同的拦截操作,比如hyRequest2的/entire/list不进行拦截,而对hyRequest2的/home/highscore进行拦截

//目录:src/request/index.ts
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"
import type { HYRequestConfig } from "./type"

class HYRequest {
  instance: AxiosInstance
  
  constructor(config: HYRequestConfig) {
    this.instance = axios.create(config)

    //使用类拦截器
    // 给每一个instance实例都添加拦截器
    this.instance.interceptors.request.use(config => {
      console.log("全局请求成功的拦截")
      return config
    }, err => {
      console.log("全局请求失败的拦截")
      return err
    })
    this.instance.interceptors.response.use(res => {
      console.log("全局响应成功拦截")
      return res.data
    }, err => {
      console.log("全局响应失败拦截")
      return err
    })

    //使用实例拦截器
    // 针对特定的hyRequest实例,比如hyRequest2,添加拦截器,
    //hyRequest2详见创建实例的目录:src/service/index.ts
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    )
      this.instance.interceptors.response.use(
        config.interceptors?.responseSuccessFn,
        config.interceptors?.responseFailureFn
      )
  }

  // 使用接口拦截器
 request<T = any>(config: HYRequestConfig<T>) {
    // 单次请求的成功拦截处理
    if (config.interceptors?.requestSuccessFn) {
      config = config.interceptors.requestSuccessFn(config)
    }

    // return this.instance.request(config)
    return new Promise<T>((resolve, reject) => {
      this.instance.request<any, T>(config).then(res => {
        // 单次响应的成功拦截处理
        if (config.interceptors?.responseSuccessFn) {
          res = config.interceptors.responseSuccessFn(res)
        }
        resolve(res)
      }).catch(err => {
        reject(err)
      })
    })
  }
}

export default HYRequest

三 创建实例

这里创建两个实例:hyRequest和hyRequest2

//目录:src/service/index.ts
import { BASE_URL, TIME_OUT } from "./config/index";
import HYRequest from "./request/index";

// 这里可以根据不同的url创建不同的实例:
// hyRequest,hyRequest1,hyRequest2···
const hyRequest = new HYRequest({
  // config/index.ts中导出的BASE_URL,TIME_OUT
  baseURL: BASE_URL,
  timeout: TIME_OUT
})

const hyRequest2 = new HYRequest({
  baseURL: "http://codercba.com:1888/airbnb/api",
  timeout: 8000,
  
  //使用实例拦截器
  interceptors: {
    requestSuccessFn: (config) => {
      console.log("爱彼迎的请求成功的拦截")
      return config
    },
    requestFailureFn: (err) => {
      console.log("爱彼迎的请求失败的拦截")
      return err
    },
    responseSuccessFn: (res) => {
      console.log("爱彼迎的响应成功的拦截")
      return res
    },
    responseFailureFn: (err) => {
      console.log("爱彼迎的响应失败的拦截")
      return err
    }
  }
})
export default hyRequest
export default hyRequest2
//目录:src/service/config/index.ts
export const BASE_URL = "http://codercba.com:8000"
export const TIME_OUT = 10000

四 发送网络请求

//目录:src/modules/home.ts
import hyRequest from "../index";

//根据数据拿到的类型
interface IHomeData {
  data: any,
  returnCode: string,
  success: boolean
}

hyRequest.request<IHomeData>({
  url: "/home/multidata"
}).then(res => {
  console.log(res)
})
//目录:src/modules/entirs.ts
import { hyRequest2 } from "..";

// "/entire/list"不添加拦截器
hyRequest2.request({
  url: "/entire/list",
  params: {
    offset: 0,
    size: 20
  }
}).then(res => {
  console.log(res)
})

//根据数据拿到的类型
interface IHighScoreData {
  list: any[],
  subtitle: string,
  title: string
  type: string,
  _id: string
}

// "/home/highscore"添加拦截器
hyRequest2.request<IHighScoreData>({
  url: "/home/highscore",
  interceptors: {
    requestSuccessFn: (config) => {
      console.log("/home/highscore请求成功的拦截")
      return config
    },
    responseSuccessFn: (res) => {
      console.log("/home/highscore响应成功的拦截")
      return res
    },
  }
}).then(res => {
  console.log(res)
})

五 运行代码

// src/index.ts

import "./service/modules/home"
import "./service/modules/entirs"
// 加入webpack依赖图,里面的代码自然可以运行

注意:TS在webpack下的运行环境在之前的文章中写过

以下是使用Vue3、TypeScript、Vite、Element Plus、Router和Axios进行请求封装,并配置开发环境、测试环境和生产环境的步骤: 1. 首先,确保你已经安装了Node.js和npm。 2. 创建一个新的Vue项目,并选择Vue3作为模板: ```shell npm create vite@latest my-project cd my-project npm install ``` 3. 安装所需的依赖包: ```shell npm install vue-router@next axios element-plus npm install --save-dev @types/node ``` 4. 在项目根目录下创建一个`.env`文件,用于配置不同环境的变量。在该文件中,可以定义不同环境下的API地址等配置信息。例如: ``` # 开发环境 VITE_API_BASE_URL=http://localhost:3000/api # 测试环境 VITE_API_BASE_URL=http://test.example.com/api # 生产环境 VITE_API_BASE_URL=http://api.example.com/api ``` 5. 创建一个`src/api`文件夹,并在其中创建一个`request.ts`文件,用于封装请求。在该文件中,可以使用Axios发送请求,并根据不同环境的配置获取API地址。例如: ```typescript import axios from 'axios'; const instance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 5000, }); export const get = (url: string, params?: any) => { return instance.get(url, { params }); }; export const post = (url: string, data?: any) => { return instance.post(url, data); }; ``` 6. 在`src/router`文件夹中创建一个`index.ts`文件,用于配置路由。在该文件中,可以定义路由的路径和对应的组件。例如: ```typescript import { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; const routes = [ { path: '/', name: 'Home', component: Home, }, // 其他路由配置... ]; const router = createRouter({ history: createWebHistory(), routes, }); export default router; ``` 7. 在`src/main.ts`文件中,引入所需的依赖,并配置Vue应用。例如: ```typescript import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; createApp(App) .use(router) .mount('#app'); ``` 8. 在`src/App.vue`文件中,使用Element Plus组件和路由进行页面渲染。例如: ```html <template> <div> <router-view></router-view> </div> </template> <script> import { defineComponent } from 'vue'; export default defineComponent({ name: 'App', }); </script> <style> /* 样式 */ </style> ``` 9. 运行开发环境: ```shell npm run dev ``` 10. 在浏览器中访问`http://localhost:3000`,即可看到Vue应用的页面。 11. 根据需要,在`src/views`文件夹中创建其他页面组件,并在路由配置中添加对应的路径和组件。 12. 根据需要,在`src/components`文件夹中创建其他组件,并在页面组件中引入和使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃炫迈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值