当前位置: 首页 > article >正文

TS axios封装

方式一

service/request/request.ts

import axios from 'axios'
import { ElLoading } from 'element-plus'
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios'
import type { ILoadingInstance } from 'element-plus/lib/el-loading/src/loading.type'

// import type { LoadingInstance } from "element-plus/lib/components/loading/src/loading"; // 按需引入

/**
 * 封装axios
 * 这里使用类进行封装是因为类具有更强的一个封装性
 * 比单纯的用函数去进行封装要更好一些
 * 使用方式:LWJRequest.get()
 */
// 拦截器类型约束--接口
// 可以让不同的类拥有不同的拦截器,更加灵活
interface InterceptorHooks {
  requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig
  requestInterceptorCatch?: (error: any) => any

  responseInterceptor?: (response: AxiosResponse) => AxiosResponse
  responseInterceptorCatch?: (error: any) => any
}

// 类接口
interface LWJRequestConfig extends AxiosRequestConfig {
  showLoading?: boolean
  interceptorHooks?: InterceptorHooks
}

// 属性接口
interface LWJData<T> {
  data: T
  returnCode: string
  success: boolean
}

// 封装请求类
class LWJRequest {
  config: AxiosRequestConfig
  interceptorHooks?: InterceptorHooks
  showLoading: boolean
  loading?: ILoadingInstance
  instance: AxiosInstance

  constructor(options: LWJRequestConfig) {
    this.config = options
    this.interceptorHooks = options.interceptorHooks
    this.showLoading = options.showLoading ?? true
    this.instance = axios.create(options)

    this.setupInterceptor()
  }

  // 拦截器函数
  setupInterceptor(): void {
    // 请求拦截
    this.instance.interceptors.request.use(
      this.interceptorHooks?.requestInterceptor,
      this.interceptorHooks?.requestInterceptorCatch
    )

    // 响应拦截
    this.instance.interceptors.response.use(
      this.interceptorHooks?.responseInterceptor,
      this.interceptorHooks?.responseInterceptorCatch
    )

    // 添加所有实例都有的拦截器--请求拦截器
    this.instance.interceptors.request.use((config) => {
      if (this.showLoading) {
        this.loading = ElLoading.service({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
      }
      return config
    })

    // 正在加载效果--响应拦截器
    this.instance.interceptors.response.use(
      (res) => {
        // setTimeout(()=>{
        //   this.loading?.close()
        // },1000)
        this.loading?.close()
        return res
      },
      (err) => {
        this.loading?.close()
        // if(err.response.status === 404){
        // }
        return err
      }
    )
  }

  // 某一个单独的请求拦截器
  request<T = any>(config: LWJRequestConfig): Promise<T> {
    if (!config.showLoading) {
      this.showLoading = false
    }
    return new Promise((resolve, reject) => {
      this.instance
        .request<any, LWJData<T>>(config)
        .then((res) => {
          resolve(res.data)
          this.showLoading = true
        })
        .catch((err) => {
          reject(err)
          this.showLoading = true
        })
    })
  }

  // 封装get请求
  get<T = any>(config: LWJRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'GET' })
  }

  // 封装post请求
  post<T = any>(config: LWJRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'POST' })
  }

  // 封装delete请求
  delete<T = any>(config: LWJRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'DELETE' })
  }

  // 封装patch请求
  patch<T = any>(config: LWJRequestConfig): Promise<T> {
    return this.request({ ...config, method: 'PATCH' })
  }
}

export default LWJRequest

service/request/config.ts

// 1.区分环境变量方式一:
// export const API_BASE_URL = 'https://coderwhy/org/dev'
// export const API_BASE_URL = 'https://coderwhy/org/prod'

// 2.区分环境变量方式二:
// let baseURL = ''
// if (process.env.NODE_ENV === 'production') {
//   baseURL = 'https://coderwhy/org/prod'
// } else if (process.env.NODE_ENV === 'development') {
//   baseURL = 'https://coderwhy/org/dev'
// } else {
//   baseURL = 'https://coderwhy/org/test'
// }

// 3.区分环境变量方式三: 加载.env文件
export const API_BASE_URL = process.env.VUE_APP_BASE_URL

export const TIME_OUT = 5000

service/request/type.ts

export interface Result<T> {
  code: number
  data: T
}

service/index.ts

// 统一出口文件

import LWJRequest from "./request/request"
import { API_BASE_URL, TIME_OUT } from './request/config'
import localCache from '@/utils/cache'

const lwjRequest = new LWJRequest({
  baseURL: API_BASE_URL,
  timeout: TIME_OUT,
  // 可以让不同的类拥有不同的拦截器,更加灵活
  interceptorHooks: {
    // 请求成功拦截
    requestInterceptor: (config) => {
      const token = localCache.getCache('token')
      if (token && config.headers) {
        config.headers.Authorization = `Bearer ${token}`
      }
      return config
    },
    // 请求失败拦截
    requestInterceptorCatch: (err) => {
      return err
    },
    // 响应成功拦截
    responseInterceptor: (res) => {
      return res.data
    },
    // 响应失败拦截
    responseInterceptorCatch: (err) => {
      return err
    }
  }
})

// export const lwjRequest2 = new LWJRequest({
//   baseURL: '地址2'
// })

export default lwjRequest

service/login/login.ts

import lwjRequest from "../index";
import {IAccount,LoginInfo} from './type'

// 枚举
enum LoginAPI {
  AccountLogin = 'login',
  UserInfo = '/users/',
  UserMenus = '/role/'
}

/**
 * 登录
 * @param account 
 * @returns 
 */
export function accountLoginRequest(account: IAccount){
  return lwjRequest.post<LoginInfo>({
    url: LoginAPI.AccountLogin,
    data: account 
  })
}

/**
 * 根据id获取用户信息
 * @param id 
 * @returns 
 */
export function requestUserInfoById(id: number){
  return lwjRequest.get({
    url: LoginAPI.UserInfo + id,
  })
}

/**
 * 根据当前用户id去请求对应的菜单
 * @param id 
 * @returns 
 */
export function requestUserMenusByRoleId(id: number) {
  return lwjRequest.get({
    url: LoginAPI.UserMenus + id + '/menu'
  })
}

service/login/type.ts

export interface IAccount {
  name: string,
  password: string
}

export interface LoginInfo {
  id: number,
  name: string,
  token:string
}

// export interface IDataType<T = any> {
//   id: number,
//   token: T
// }

utils/cache.ts

// 封装本地存储方法
class LocalCache {
  setCache(key: string, value: any) {
    window.localStorage.setItem(key, JSON.stringify(value))
  }

  getCache(key: string) {
    const value = window.localStorage.getItem(key)
    if (value) {
      return JSON.parse(value)
    }
  }

  deleteCache(key: string) {
    window.localStorage.removeItem(key)
  }

  clearLocal() {
    window.localStorage.clear()
  }
}

export default new LocalCache()

方式二

service/config/index.ts

// 1.区分开发环境和生产环境
// export const BASE_URL = 'http://aaa.dev:8000'
// export const BASE_URL = 'http://aaa.prod:8000'

// 2.代码逻辑判断, 判断当前环境
// vite默认提供的环境变量
// console.log(import.meta.env.MODE)
// console.log(import.meta.env.DEV); // 是否开发环境
// console.log(import.meta.env.PROD); // 是否生产环境
// console.log(import.meta.env.SSR); // 是否是服务器端渲染(server side render)

let BASE_URL = "";
if (import.meta.env.PROD) {
  // 生产环境
  BASE_URL = "http://152.136.185.210:4000";
} else {
  // 开发环境
  BASE_URL = "http://152.136.185.210:5000";
}

// console.log(BASE_URL);

// 3.通过创建.env文件直接创建变量
// console.log(import.meta.env.VITE_URL);

export const TIME_OUT = 10000;
export { BASE_URL };

service/request/index.ts

import axios from "axios";
import type { AxiosInstance } from "axios";
import type { LWJRequestConfig } from "./type";

// 拦截器: 蒙版Loading/token/修改配置

/**
 * 两个难点:
 *  1.拦截器进行精细控制
 *    > 全局拦截器
 *    > 实例拦截器
 *    > 单次请求拦截器
 *
 *  2.响应结果的类型处理(泛型)
 */

class LWJRequest {
  instance: AxiosInstance;

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

    // 每个instance实例都添加拦截器
    this.instance.interceptors.request.use(
      (config) => {
        // loading/token
        return config;
      },
      (err) => {
        return err;
      }
    );
    this.instance.interceptors.response.use(
      (res) => {
        return res.data;
      },
      (err) => {
        return err;
      }
    );

    // 针对特定的LWJRequest实例添加拦截器
    this.instance.interceptors.request.use(
      config.interceptors?.requestSuccessFn,
      config.interceptors?.requestFailureFn
    );
    this.instance.interceptors.response.use(
      config.interceptors?.responseSuccessFn,
      config.interceptors?.responseFailureFn
    );
  }

  // 封装网络请求的方法
  // T => IHomeData
  request<T = any>(config: LWJRequestConfig<T>) {
    // 单次请求的成功拦截处理
    if (config.interceptors?.requestSuccessFn) {
      config = config.interceptors.requestSuccessFn(config);
    }

    // 返回Promise
    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);
        });
    });
  }

  get<T = any>(config: LWJRequestConfig<T>) {
    return this.request({ ...config, method: "GET" });
  }
  post<T = any>(config: LWJRequestConfig<T>) {
    return this.request({ ...config, method: "POST" });
  }
  delete<T = any>(config: LWJRequestConfig<T>) {
    return this.request({ ...config, method: "DELETE" });
  }
  patch<T = any>(config: LWJRequestConfig<T>) {
    return this.request({ ...config, method: "PATCH" });
  }
}

export default LWJRequest;

service/request/type.ts

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

// 针对AxiosRequestConfig配置进行扩展
export interface LWJInterceptors<T = AxiosResponse> {
  requestSuccessFn?: (config: AxiosRequestConfig) => AxiosRequestConfig;
  requestFailureFn?: (err: any) => any;
  responseSuccessFn?: (res: T) => T;
  responseFailureFn?: (err: any) => any;
}

export interface LWJRequestConfig<T = AxiosResponse>
  extends AxiosRequestConfig {
  interceptors?: LWJInterceptors<T>;
}

service/index.ts

import { LOGIN_TOKEN } from '@/global/constants'
import { localCache } from '@/utils/cache'
import { BASE_URL, TIME_OUT } from './config'
import LWJRequest from './request'

const lwjRequest = new LWJRequest({
  baseURL: BASE_URL,
  timeout: TIME_OUT,
  interceptors: {
    requestSuccessFn: (config) => {
      // 每一个请求都自动携带token
      const token = localCache.getCache(LOGIN_TOKEN)
      if (config.headers && token) {
        // 类型缩小
        config.headers.Authorization = 'Bearer ' + token
      }
      return config
    }
  }
})

export default lwjRequest

src/global/constants.ts

export const LOGIN_TOKEN = 'login/token'

src/utils/cache.ts

enum CacheType {
  Local,
  Session
}

class Cache {
  storage: Storage

  constructor(type: CacheType) {
    this.storage = type === CacheType.Local ? localStorage : sessionStorage
  }

  setCache(key: string, value: any) {
    if (value) {
      this.storage.setItem(key, JSON.stringify(value))
    }
  }

  getCache(key: string) {
    const value = this.storage.getItem(key)
    if (value) {
      return JSON.parse(value)
    }
  }

  removeCache(key: string) {
    this.storage.removeItem(key)
  }

  clear() {
    this.storage.clear()
  }
}

const localCache = new Cache(CacheType.Local)
const sessionCache = new Cache(CacheType.Session)

export { localCache, sessionCache }

service/login/index.ts

import hyRequest from '..'
import type { IAccount } from '@/types'
// import { localCache } from '@/utils/cache'
// import { LOGIN_TOKEN } from '@/global/constants'

export function accountLoginRequest(account: IAccount) {
  return hyRequest.post({
    url: '/login',
    data: account
  })
}

export function getUserInfoById(id: number) {
  return hyRequest.get({
    url: `/users/${id}`
    // headers: {
    //   Authorization: 'Bearer ' + localCache.getCache(LOGIN_TOKEN)
    // }
  })
}

export function getUserMenusByRoleId(id: number) {
  return hyRequest.get({
    url: `/role/${id}/menu`
  })
}

http://www.kler.cn/a/301757.html

相关文章:

  • 【珠海科技学院主办,暨南大学协办 | IEEE出版 | EI检索稳定 】2024年健康大数据与智能医疗国际会议(ICHIH 2024)
  • Android笔记(三十七):封装一个RecyclerView Item曝光工具——用于埋点上报
  • Vue学习记录03
  • 利用云计算实现高效的数据备份与恢复策略
  • 【优选算法 — 滑动窗口】水果成篮 找到字符串中所有字母异位词
  • Tensorflow基本概念
  • FinOps原则:云计算成本管理的关键
  • Chainlit集成Langchain并使用通义千问实现和数据库交互的网页对话应用增强扩展(text2sql)
  • 高教社杯数模竞赛特辑论文篇-2015年D题:众筹筑屋规划方案设计
  • AI教你学Python 第1天:Python简介与环境配置
  • Python和MATLAB及C++信噪比导图(算法模型)
  • 解开密码锁的最少次数
  • cesium.js 入门到精通(1)
  • 高级java每日一道面试题-2024年9月08日-前端篇-JS的执行顺序是什么样的?
  • php实现kafka
  • 一篇文章,讲清SQL的 joins 语法
  • Java贪心算法每日一题——179.最大数
  • 【QT】Qt窗口
  • Pr:序列设置 - VR 视频
  • 【区块链 + 基层治理】社区防疫管理平台 | FISCO BCOS应用案例
  • 404 error when doing workload anlysis using locust on OpenAI API (GPT.35)
  • 【深度学习 Pytorch】深入浅出:使用PyTorch进行模型训练与GPU加速
  • 泛零售行业的营销自动化现状如何?
  • Vue3+vite使用i18n国际化
  • 军事目标无人机视角检测数据集 3500张 坦克 带标注voc
  • 剖析 MySQL 数据库连接池(C++版)