vue3+ts axios请求封装,API统一管理

支持取消重复请求

httpClient.ts全部代码

import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { TResponseData } from '@/types/global/request'
import { Local } from '@/utils/storage'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/user'
class Api {
  instance: AxiosInstance
  config: AxiosRequestConfig

  constructor(option: AxiosRequestConfig) {
    this.config = option
    // 配置全局参数
    this.instance = axios.create(this.config)
    this.interceptors()
  }

  interceptors() {
    this.instance.interceptors.request.use(
      (config) => {
        removePending(config)

        addPending(config)

        const token = Local.get('ACCESS_TOKEN')
        if (token) {
          //@ts-ignore
          config.headers.Authorization = token
        }
        return config
      },
      (error) => Promise.reject(error)
    )

    this.instance.interceptors.response.use(
      (response) => {
        removePending(response.config)

        const res = response.data
        if (res.code !== 1) {
          ElMessage.error(res.msg)
        }
        return res
      },
      (error) => {
        error.config && removePending(error.config)
        httpErrorStatusHandle(error)
        return Promise.reject(error)
      }
    )
  }
  async request<T = any>(config: AxiosRequestConfig): Promise<TResponseData<T>> {
    return this.instance.request<TResponseData<T>, TResponseData<T>>(config)
  }
}

const api = new Api({
  baseURL: '/api',
  timeout: 10 * 1000,
})

export default api

/**
 * 处理异常
 * @param {*} error
 */
function httpErrorStatusHandle(error: any) {
  const userStore = useUserStore()
  // 处理被取消的请求
  if (axios.isCancel(error)) return console.error('请求的重复请求:' + error.message)
  let message = ''
  if (error && error.response) {
    switch (error.response.status) {
      case 302:
        message = '接口重定向了!'
        break
      case 400:
        message = '参数不正确!'
        break
      case 401:
        userStore.clearLoginInfo()
        message = '您未登录,或者登录已经超时,请先登录!'
        break
      case 403:
        message = '您没有权限操作!'
        break
      case 404:
        message = `请求地址出错: ${error.response.config.url}`
        break // 在正确域名下
      case 408:
        message = '请求超时!'
        break
      case 409:
        message = '系统已存在相同数据!'
        break
      case 500:
        message = '服务器内部错误!'
        break
      case 501:
        message = '服务未实现!'
        break
      case 502:
        message = '网关错误!'
        break
      case 503:
        message = '服务不可用!'
        break
      case 504:
        message = '服务暂时无法访问,请稍后再试!'
        break
      case 505:
        message = 'HTTP版本不受支持!'
        break
      default:
        message = '异常问题,请联系管理员!'
        break
    }
  }
  if (error.message.includes('timeout')) message = '网络请求超时!'
  if (error.message.includes('Network'))
    message = window.navigator.onLine ? '服务端异常!' : '您断网了!'

  ElMessage({
    type: 'error',
    message,
  })
}

const pendingMap = new Map()

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 * @param {*} config
 */
function addPending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel)
      }
    })
}

/**
 * 删除重复的请求
 * @param {*} config
 */
function removePending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config)
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey)
    // 如你不明白此处为什么需要传递pendingKey可以看文章下方的补丁解释
    cancelToken(pendingKey)
    pendingMap.delete(pendingKey)
  }
}

/**
 * 生成唯一的每个请求的唯一key
 * @param {*} config
 * @returns
 */
function getPendingKey(config: AxiosRequestConfig) {
  let { url, method, params, data } = config
  if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}

统一封装后端返回模型

// 后端统一返回数据模型
export type TResponseData<T> = {
  code: 0 | number // 0 => ok
  msg: string
  data: T
}

// 后端分页数据模型
export type PageData<T = any> = {
  total: 0 | number
  records: Array<T>
}

怎么使用

新建一个user.ts文件

import http from './httpClient'
import { PageData } from '@/types/global/request'
import { UserInfo } from '@/types/user'

class UserApi {
  /**
   * 获取分页表格数据
   * @param params 查询参数
   * @returns
   */
  getPageData(params: object) {
    return http.request<PageData<UserInfo>>({
      url: '/sys/userInfo/page',
      method: 'GET',
      params,
    })
  }

  /**
   * 根据id删除
   * @param id id
   * @returns
   */
  removeById(id: string) {
    return http.request({
      url: '/sys/userInfo/removeById/' + id,
      method: 'DELETE',
    })
  }

  /**
   * 保存接口
   * @param params 保存参数
   * @returns
   */
  saveOrUpdate(params: object) {
    return http.request({
      url: '/sys/userInfo/saveOrUpdate',
      method: 'POST',
      data: params,
    })
  }
}

const userApi = new UserApi()

export default userApi

页面怎么调用

<template>
...
</template>
<script lang="ts" setup>
import userApi from '@/api/user'

    const queryData = async () => {
        const res = await userApi.getPageData(params)
    }

</script>

这样vscode就可以很完美的代码提示了

 

可以直接复制使用,如果有帮到你,打个赏吧!

完结!

 

 

  • 8
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是封装Vue3 + TypeScript + Axios的示例代码: 1. 创建一个`api.ts`文件,用于存放API请求路径: ```typescript // api.ts const BASE_URL = 'https://api.example.com'; export const API_PATHS = { getUsers: `${BASE_URL}/users`, getPosts: `${BASE_URL}/posts`, // 添加其他API路径... }; ``` 2. 创建一个`request.ts`文件,用于封装Axios请求方法: ```typescript // request.ts import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import { API_PATHS } from './api'; // 创建一个Axios实例 const instance = axios.create({ baseURL: API_PATHS.BASE_URL, timeout: 5000, // 设置请求超时时间 }); // 请求拦截器 instance.interceptors.request.use( (config: AxiosRequestConfig) => { // 在请求发送之前可以进行一些处理,例如添加请求头等 return config; }, (error: any) => { // 处理请求错误 return Promise.reject(error); } ); // 响应拦截器 instance.interceptors.response.use( (response: AxiosResponse) => { // 在接收到响应数据之前可以进行一些处理,例如解析响应数据等 return response.data; }, (error: any) => { // 处理响应错误 return Promise.reject(error); } ); // 封装GET请求方法 export const get = (url: string, params?: any) => { return instance.get(url, { params }); }; // 封装POST请求方法 export const post = (url: string, data?: any) => { return instance.post(url, data); }; // 添加其他请求方法,例如PUT、DELETE等... ``` 3. 在需要使用Axios的地方,引入`request.ts`并调用封装请求方法: ```typescript import { get, post } from './request'; // 使用GET请求获取用户列表 get(API_PATHS.getUsers) .then((response: any) => { // 处理响应数据 console.log(response); }) .catch((error: any) => { // 处理请求错误 console.error(error); }); // 使用POST请求创建新用户 const newUser = { name: 'John', age: 25 }; post(API_PATHS.getUsers, newUser) .then((response: any) => { // 处理响应数据 console.log(response); }) .catch((error: any) => { // 处理请求错误 console.error(error); }); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值