05-vue3+ts中axios的封装

vue3+ts中axios的封装

安装 axios

bash 复制代码
npm install axios

一、axios 的类型解析

Axios 几个常用类型:

  • AxiosInstance: axios 实例类型
  • AxiosRequestConfig: axios 请求配置类型
  • AxiosResponse: axios 响应类型
  • AxiosError: axios 错误类型

1、AxiosRequestConfig

AxiosRequestConfig 是我们使用 axios 发送请求传递参数的类型。当然它也是我们请求拦截器里面的参数类型。

2、AxiosInstance

  • AxiosInstance 是 axios 的实例类型。
  • axios.create(config?: AxiosRequestConfig)创建出来的对象都是AxiosInstance类型!

3、AxiosResponse

  • AxiosResponse 是 axios 响应类型。
  • 我们可以在响应拦截器中获取到响应数据。
ts 复制代码
export interface AxiosResponse<T = any>  {
  // 后端接口数据
  data: T;
  // http状态码
  status: number;
  // 来自服务器响应的 HTTP 状态信息
  statusText: string;
  // 响应头
  headers: any;
  // 请求配置信息
  config: AxiosRequestConfig;
  // 请求
  request?: any;
}

4、AxiosError

AxiosError 是 axios 错误类型。可以在请求或响应拦截器中获取到错误信息。

二、封装axios

本质:axios二次封装,就是使用请求和响应拦截器!

1、步骤

  • 1.创建axios实例: axios.create(config配置对象)
  • 2.axios添加请求拦截器:主要是操作config对象:
js 复制代码
axios.interceptors.request.use((config)=>{return config})
  • 3.响应拦截器
js 复制代码
axios.interceptors.response.use((response)=>{return response})

2、实现代码

  • 基于restful风格,提供了相对应的方法,方便调用!
  • 在src目录下,创建api目录,创建request.ts,代码如下:
ts 复制代码
import axios from "axios";
import type { AxiosInstance, AxiosRequestConfig } from "axios";
import { base_url, TOKEN } from "@/config/com/base";
import toast from "@/config/utils/toast";
import { ElLoading } from "element-plus";
import useLoginStore from "@/store/login_store";
import cache from "@/config/utils/cache";
import router from "@/router";
/**
 * axios二次封装,就是使用请求和响应拦截器
 * --- 创建axios对象: axios.create(config配置对象)
 * --- 给axios添加请求拦截器:主要是操作config对象
 *      axios.interceptors.request.use((config)=>{return config})
 * --- 给axios添加响应拦截器:
 *      request.interceptors.response.use();
 * ---------------------------------------------------------
 * -- 定义一个Request类:两个属性
 *    --- 属性:instance:AxiosInstance类型
 *              axios的实例对象
 *    --- 属性:baseConfig: AxiosRequestConfig类型
 *              基本的配置信息:baseURL,timeout
 *    --- 属性:
 * ---------------------------------------------------------
 *  */

// 定义一个类Request!
class Request {
  //axios.create()返回axios对象
  instance: AxiosInstance;
  loadingInstance: any; // 用于存储ElLoading实例的变量
  //axios.create(config配置对象)需要的config
  baseConfig: AxiosRequestConfig = { baseURL: base_url, timeout: 5000 };
  constructor(config: AxiosRequestConfig) {
    // 还得提供额外的config配置!所以使用了Object.assign()
    this.instance = axios.create(Object.assign(this.baseConfig, config));
    //在构造器初始化时候 添加 请求拦截器: 主要操作config对象
    this.instance.interceptors.request.use(
      (config: any) => {
        // 创建ElLoading实例并显示加载提示,这里可以配置一些加载提示的相关属性,比如文本、背景遮罩等
        this.loadingInstance = ElLoading.service({
          text: "正在加载...",
          fullscreen: true,
          background: "rgba(0, 0, 0, 0.05)",
        });
        //添加token:
        const userStore = useLoginStore();
        let token = userStore.token;
        if (token) {
          config.headers["Authorization"] = `Bearer ${token}`;
        }
        return config;
      },
      (error) => {// 请求错误,这里可以用全局提示框进行提示
        return Promise.reject(error);
      }
    );
    this.instance.interceptors.response.use( // 添加响应拦截器
      (res: any) => {
        // console.log('request.ts --- 响应拦截器:'+res);
        // 关闭ElLoading实例,隐藏加载提示
        if (this.loadingInstance) {
          this.loadingInstance.close();
        }
        return res.data;
      },
      // 失败响应
      (err: any) => {
        // 这里是AxiosError类型,所以一般我们只reject我们需要的响应即可
        // 关闭ElLoading实例,隐藏加载提示
        if (this.loadingInstance) {
          this.loadingInstance.close();
        }
        console.log("拦截器--error=" + JSON.stringify(err.response.data.data));
        let message = "";
        switch (err.response.status) {
          case 400:
            message = "code = 400 :" + JSON.stringify(err.response.data.data);
            break;
          case 401:
            console.log("401---token认证失败---");
            message = err.response.data.data?.detail;
            // 这里可以做清空storage并跳转到登录页的操作,处理只需要清空token即可,
            cache.removeCache(TOKEN);
            router.replace("/login");
            // 强制刷新
            window.location.reload();
            break;
          case 403:
            message = "权限不够,拒绝访问(403)";
            break;
          case 404:
            message = "请求地址无效(404)";
            break;
          case 405:
            message = "请求方法不被允许(405)";
            break;
          case 500:
            message = "服务器错误(500)";
            break;
          default:
            message = `连接出错(${err.response.status})!`;
        }
        // 错误消息可以使用全局弹框展示出来 :比如element plus 可以使用 ElMessage
        // `${message},请检查网络或联系管理员!`
        if (err.response.data.data) {
          // toast.error(message + " : " + JSON.stringify(err.response.data.data));
          toast.error(message);
        } else {
          toast.error(message + " : " + "服务器好像没有开启");
        }
        return Promise.reject(err.response);
      }
    );
  }
  // 封装get请求!
  public get(url: string, params?: any): Promise<any> {
    return this.instance.get(url, { params });
  }
  public get_by_id(url: string, id: Number): Promise<any> {
    return this.instance.get(url + id + "/");
  }
  // 封装post请求!保存操作
  public post(url: string, data: any): Promise<any> {
    return this.instance.post(url, data);
  }
  // 封装put请求!
  public put(url: string, data: any): Promise<any> {
    return this.instance.put(url + data.id + "/", data);
  }
  // 根据id删除的方法(资源地址,资源id)
  public delete_by_id(url: string, id: Number): Promise<any> {
    return this.instance.delete(url + id + "/");
  }
  // 根据pic删除的方法:把参数封装到params配置项中
  public delete_pic(url: string, params?: any): Promise<any> {
    return this.instance.delete(url, { params });
  }
  // 把参数封装到data配置项中
  public delete_selected(url: string, data?: any): Promise<any> {
    return this.instance.delete(url, { data });
  }
}
// 默认导出Request实例!
export default new Request({});

封装中使用到的其它依赖文件:

  • base.ts
csharp 复制代码
import { base_url, TOKEN } from "@/config/com/base";
ts 复制代码
// 配置项目的基本信息的文件
//特别注意。图片路径最后要添加斜杠!不然图片显示失败
export const base_url: string = import.meta.env.VITE_APP_BASE_API;
export const TOKEN = "token";
  • toast.ts : 是对Elment-plus的提示信息的封装(个人选择)
ts 复制代码
import toast from "@/config/utils/toast";
ts 复制代码
// 用于封装一些全局的hook,可以单独导入某些方法使用,也可以统一导入 hook 对象,从 hook 对象中 . 具体的方法
import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
/**
 * 封装一个全局的 message 方法,用于显示消息提示
 * @param message  消息内容
 * @param type 消息类型,默认为 success
 */
export const message = (message: string) => {
  ElMessage({
    message,
    type: "success",
  });
};
/**
 * 封装一个全局的 notification 方法,用于显示通知
 *  @param message 通知内容
 *  @param title   通知标题,默认为 '提示'
 */
export const notify = (message: string) => {
  ElNotification({
    // title,
    message,
    type: "success",
  });
};
export const error = (message: string) => {
  ElNotification({
    message,
    type: "error",
  });
};
/**
 * 封装一个全局的 confirm 方法,用于显示确认对话框
 * @param message 对话框内容
 * @param title 对话框标题,默认为 '提示'
 * @param [options] 对话框选项
 * @return Promise<boolean>
 */
export const confirm = (message: string, title = "提示", options: any = {}) => {
  if (Object.keys(options).length == 0) {
    options = {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    };
  }
  return new Promise((resolve, reject) => {
    ElMessageBox.confirm(message, title, options)
      .then(() => {
        resolve(true);
      })
      .catch(() => {
        reject(false);
      });
  });
};
/**
 * 统一导出一个 hook 方法对象,包含所有 hook 方法
 */
export default {
  message,
  confirm,
  notify,
  error,
};
/**
 * 使用该hooks方式如下:
import hooks from "@/config/utils/index";
hooks.message('操作成功') // 成功弹出
hooks.notification('恭喜你学会了使用全局通知组件', '操作成功', { type: 'success' }) // 成功弹出
hooks.confirm('确认要删除吗?').then((res) => console.log(res)) // 成功弹出
 */
  • login_store.ts : 仅给出示例代码
csharp 复制代码
import useLoginStore from "@/store/login_store";
csharp 复制代码
import { defineStore } from "pinia";
import { TOKEN } from "@/config/com/base";
import cache from "@/config/utils/cache";
import { ref } from "vue";
export const useLoginStore = defineStore("login", () => {
    const token = ref("");
    const login = () => {
        // 实现逻辑
    };
    return {
        token,
        login
    }
});
  • cache.ts : 这是封装的localstorage使用的工具类!
csharp 复制代码
import cache from "@/config/utils/cache";
ts 复制代码
/**
 * 封装localStorage的使用:
 * import cache from "@/config/utils/cache";
 * cache.xxx()即可!
 */
class Cache {
  setCache(key: string, value: any) {
    if (value) {
      localStorage.setItem(key, JSON.stringify(value));
    }
  }
  getCache(key: string) {
    const value = localStorage.getItem(key);
    if (value) {
      return JSON.parse(value);
    }
    return "";
  }
  removeCache(key: string) {
    localStorage.removeItem(key);
  }
  clear() {
    localStorage.clear();
  }
}
export default new Cache();

3、发送请求的示例代码:

以下代码是使用request的格式示例:

  • 发送请求即可复制格式,修改参数即可!
ts 复制代码
import request from "@/api/request";

// 以下 用到的请求地址示例:
//  api_sy.user = "/sy/user/", //操作用户的url
// 表单数据
let form = reactive({
	id:xxxx, //修改时候传递!
    username: "",
    password: "",
    name: "",
    phone: '',
    is_active: true,
    is_staff: true,
    avatar: "",
})

发送get请求:

ts 复制代码
// 发送get请求
request.get(api_sy.user, params).then(resp => {
	console.log(resp.data)
})

发送post请求:

ts 复制代码
// 发送post请求
request.post(api_sy.user, form).then(resp => {
	console.log(resp.data)
})

发送put请求:

ts 复制代码
// 发送put请求
request.put(api_sy.user, form).then(resp => {
	console.log(resp.data)
})

发送delete请求:

ts 复制代码
// 发送delete请求
request.delete_by_id(api_sy.user, id).then(resp => {
	console.log(resp.data)
})
相关推荐
JiKun2 小时前
ECMA 2024(ES15) 新特性
前端·javascript
百锦再3 小时前
从 .NET 到 Java 的转型指南:详细学习路线与实践建议
android·java·前端·数据库·学习·.net·数据库架构
i小杨3 小时前
前端埋点(打点)方案
前端·状态模式
前端加油站3 小时前
时间转换那些事
前端·javascript
风清云淡_A3 小时前
【VUECLI】node.js打造自己的前端cli脚手架工具
前端·node.js
YuspTLstar3 小时前
一文掌握Redux-toolkit核心原理
前端·react.js
云枫晖3 小时前
手写Promise-静态方法all和allSettled
前端·javascript
weixin_456904273 小时前
前端开发时npm install报错解决方案
前端·npm·node.js
东华帝君4 小时前
Object.create继承
前端