您现在的位置是:首页 >技术教程 >【Axios、TypeScript】基于vue3和typescript的axios二次封装网站首页技术教程

【Axios、TypeScript】基于vue3和typescript的axios二次封装

起伏羊 2024-06-17 10:22:18
简介【Axios、TypeScript】基于vue3和typescript的axios二次封装

准备

截屏2023-05-14 21.10.35.png

  • 创建vue3项目
  • 在 src 的文件下创建 发送网络请求相关的 文件夹 ?️ service

?️ service 包含有:

? request

?️ index.ts

使用 class把封装 axios 封装成一个类,导出这个类

类型问题:

axios.create类型:
截屏2023-05-15 10.28.59.png
拦截器类型问题:
截屏2023-05-14 22.57.56.png

封装代码

import axios from 'axios'
import type { AxiosInstance } from 'axios'
// 拦截器:loading、token、修改配置
// AxiosRequestConfig类型中没有 interceptors 需要扩展类型
import PKRequestConfig from './type'

class PKRequest {
  instance: AxiosInstance
  constructor(config: PKRequestConfig) {
    // 每个实例都会 创建axios 
    this.instance = axios.create(config)

    //   实例 全局的拦截器
    this.instance.interceptors.request.use(
      (config) => {
        console.log('实例-> 全局的请求成功的拦截:')
        return config
      },
      (err) => {
        console.log('实例-> 全局的请求失败的拦截:')
        return err
      }
    )
    this.instance.interceptors.response.use(
      (res) => {
        console.log('实例-> 全局的响应成功的拦截:')
        //  res.data => promise的res类型有问题 : 通过泛型解决
        return res
      },
      (err) => {
        console.log('实例-> 全局的响应失败的拦截:')
        return err
      }
    )
    //   针对特定的pkRequest实例添加拦截
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailedFn
    )
    this.instance.interceptors.response.use(
      config.interceptors?.reponseSuccessFn,
      config.interceptors?.reponseFailedFn
    )
  }
  // 网络请求泛型; 因为promise的成功的回调 返回的类型 是创建实例时确定的
  // PKRequestConfig<T> : PKRequestConfig中的拦截器 响应成功的返回数据类型需要和 promise一致
  request<T = any>(config: PKRequestConfig<T>) {
    // 针对网络请求 中,有 拦截器
    if (config.interceptors?.requestSuccessFn) {
      // 单次请求的成功拦截
      config.interceptors.requestSuccessFn(config as any)
    }
    // 返回的promise
    return new Promise<T>((resolve, reject) => {
      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.reponseSuccessFn) {
            res = config.interceptors.reponseSuccessFn(res)
          }
          resolve(res)
        })
        .catch((err) => {
          reject(err)
        })
    })
  }


  get<T = any>(config: PKRequestConfig<T>) {
    return this.request({ ...config, method: 'GET' })
  }
  post<T = any>(config: PKRequestConfig<T>) {
    return this.request({ ...config, method: 'POST' })
  }
  delete<T = any>(config: PKRequestConfig<T>) {
    return this.request({ ...config, method: 'DELETE' })
  }
  put<T = any>(config: PKRequestConfig<T>) {
    return this.request({ ...config, method: 'PUT' })
  }
  patch<T = any>(config: PKRequestConfig<T>) {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default PKRequest
import type { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
// 扩展 AxiosRequestConfig类型
interface PKInterceptors<T = AxiosResponse> {
  requestSuccessFn?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig
  requestFailedFn?: (err: any) => any
  reponseSuccessFn?: (res: T) => T
  reponseFailedFn?: (err: any) => any
}
interface PKRequestConfig<T = AxiosResponse> extends AxiosRequestConfig {
  interceptors?: PKInterceptors<T>
}
export default PKRequestConfig

? config

?️ index.ts 主要写配置

export const BASE_URL = 'http://www.zkt-it.com:5050'
export const TIME_OUT = 10000
// 测试登录获取token
export const BASE_URL2 = 'http://codercba.com:5000'

? index.ts

创建 PKRequest 的实例。实例可以有多个
例如:

import PKRequest from './request'
import { BASE_URL, TIME_OUT } from './config/index'


// pkRequest实例
const pkRequest = new PKRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT
})


// 实例2
export const pkRequest2 = new PKRequest({
  baseURL: 'https://api.oioweb.cn/api/common',
  timeout: 8000,
  // 单独的拦截器
  // AxiosRequestConfig类型中没有 interceptors
  interceptors: {
    requestSuccessFn: (config) => {
      console.log('pkRequest2单独拦截器:请求成功的拦截')
      return config
    },
    requestFailedFn: (err) => {
      console.log('pkRequest2单独拦截器:请求失败的拦截')
      return err
    },
    reponseSuccessFn: (res) => {
      console.log('pkRequest2单独拦截器:响应成功的拦截')
      return res
    },
    reponseFailedFn: (err) => {
      console.log('pkRequest2单独拦截器:响应失败的拦截')
      return err
    }
  }
})
// 实例3:登录 BASE_URL2
export const pkRequest3 = new PKRequest({
  baseURL: BASE_URL2,
  timeout: 3000
})
export default pkRequest

? module

?️ index.ts

import('./home')
import('./year')
import('./gettest')
import('./login')

?️ home.ts

import pkRequest from '..'
// home.ts 
// 根据请求数据设置数据类型
interface INews {
  data: any[]
  status: number
  statusText: string
  config: object
  headers: any
  request: any
}
pkRequest
  .request<INews>({
    url: '/news'
  })
  .then((res) => {
    // 通过泛型设置,此时的res类型为 INews
    console.log('pkRequest1:新闻', res.data, res.status)
  })


pkRequest
  .request({ //没有特别写类型,则是泛型的默认值 any
    url: '/mingxing',
    interceptors: {
      requestSuccessFn: (config) => {
        console.log('/mingxing 请求成功的拦截 :')
        return config
      },
      reponseSuccessFn: (res) => {
        console.log('/mingxing 响应成功的拦截 :')
        return res
      }
    }
  })
  .then((res) => {
    console.log('pkRequest1:明星', res)
  })

?️ year.ts

import { pkRequest2 } from '..'
// year.ts

pkRequest2
  .request({
    url: '/history'
  })
  .then((res) => {
    console.log('pkRequest2:历史上的今天', res)
  })

?️ login.ts

import { pkRequest3 } from '..'


const postLoginRequest = async () => {
  const res = await pkRequest3.post({
    url: '/login',
    data: {
      name: 'coderwhy',
      password: '123456'
    }
  })
  console.log('登录用户信息:')
  console.table(res.data.data)
}

postLoginRequest()

输出结果

截屏2023-05-15 10.49.59.png

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。