Axios 之 ts 版本的哀求封装

打印 上一主题 下一主题

主题 782|帖子 782|积分 2346

1、安装

  1. npm install axios
复制代码
文档链接:中文文档
2、常用封装

2.1 简单版本的封装

这里仅封装常用的 get、post、put、delete 几种方法
且只封装几种常见的报错提示
src/utils/request.ts
  1. import axios, {
  2.   AxiosError,
  3.   AxiosInstance,
  4.   AxiosResponse,
  5.   InternalAxiosRequestConfig,
  6. } from "axios";
  7. const config = {
  8.   baseURL: "http://localhost:3000/api",
  9.   timeout: 10000,
  10.   withCredentials: true,
  11.   headers: {},
  12. };
  13. class RequestHttp {
  14.   service: AxiosInstance;
  15.   constructor() {
  16.     this.service = axios.create(config);
  17.     /**
  18.      * @description 请求拦截器
  19.      */
  20.     this.service.interceptors.request.use(
  21.       (config: InternalAxiosRequestConfig) => {
  22.         return config;
  23.       }
  24.     );
  25.     /**
  26.      * @description 响应拦截器
  27.      */
  28.     this.service.interceptors.response.use(
  29.       (response: AxiosResponse) => {
  30.         const { data } = response;
  31.         return data;
  32.       },
  33.       (error: AxiosError) => {
  34.         const { response } = error;
  35.         if (response) {
  36.           checkStatus(response.status);
  37.         }
  38.         return false;
  39.       }
  40.     );
  41.   }
  42.   // 常用请求方法封装
  43.   get(url: string, params?: object, _object = {}) {
  44.     return this.service.get(url, { params, ..._object });
  45.   }
  46.   post(url: string, params?: object, _object = {}) {
  47.     return this.service.post(url, params, _object);
  48.   }
  49.   put(url: string, params?: object, _object = {}) {
  50.     return this.service.put(url, params, _object);
  51.   }
  52.   delete(url: string, params?: any, _object = {}) {
  53.     return this.service.delete(url, { params, ..._object });
  54.   }
  55. }
  56. /**
  57. * @description: 校验网络请求状态码
  58. * @param {Number} status
  59. * @return void
  60. */
  61. const checkStatus = (status: number): void => {
  62.   switch (status) {
  63.       case 404:
  64.           console.warn("资源不存在!");
  65.           break;
  66.       case 405:
  67.           console.warn("请求方式错误!");
  68.           break;
  69.       case 500:
  70.           console.warn("服务器异常!");
  71.           break;
  72.       default:
  73.           console.warn("请求失败!");
  74.   }
  75. };
  76. const request = new RequestHttp();
  77. export default request;
复制代码
2.1 包罗多处置惩罚的封装

增加如下处置惩罚

  • 哀求loading
  • 取消哀求(CancelToken)
  • 哀求效果的更细节处置惩罚
src/utils/request.ts
  1. import { message } from "antd";
  2. import axios, {
  3.   AxiosInstance,
  4.   InternalAxiosRequestConfig,
  5.   AxiosResponse,
  6.   AxiosError,
  7. } from "axios";
  8. import { store } from "@/redux";
  9. import { ResponseCodeEnum } from "@/enums/httpEnum";
  10. import { setToken } from "@/redux/modules/global";
  11. import { ResultData } from "@/api/types/index.type";
  12. import fullLoading from "./fullLoading";
  13. import { AxiosCancel } from "./AxiosCancel";
  14. const config = {
  15.   baseURL: "http://localhost:3000/api",
  16.   timeout: 5000,
  17.   withCredentials: true,
  18.   headers: {},
  19. };
  20. const axiosCancel = new AxiosCancel();
  21. class RequestHttp {
  22.   service: AxiosInstance;
  23.   constructor() {
  24.     this.service = axios.create(config);
  25.     /**
  26.      * @description 请求拦截器
  27.      */
  28.     this.service.interceptors.request.use(
  29.       (config: InternalAxiosRequestConfig) => {
  30.         console.log(config)
  31.         // 打开全局 loading
  32.         // 如不需要全局 loading,则第三个参数  { headers: { noLoading: true } }
  33.         if(!config.headers.noLoading) {
  34.           fullLoading.show();
  35.         }
  36.         // 将请求添加到 pending 中
  37.         axiosCancel.addPending(config);
  38.         // 这里如果需要添加token
  39.         const token = store.getState().global.token; // 我这里用的是 react-redux + redux-toolkit
  40.         config.headers["X-Access-Token"] = token;
  41.         return config;
  42.       }
  43.     );
  44.     /**
  45.      * @description 响应拦截器
  46.      */
  47.     this.service.interceptors.response.use(
  48.       (response: AxiosResponse) => {
  49.         const { data, config } = response;
  50.         // 关闭全局 loading
  51.         if(!config.headers.noLoading) {
  52.           fullLoading.hide();
  53.         }
  54.         // 请求结束,移除本次请求
  55.         axiosCancel.removePending(config.url, config.method);
  56.         // 接口返回 code 不是 200 的处理
  57.         if (data.code !== ResponseCodeEnum.SUCCESS) {
  58.           message.error(data.msg);
  59.           // 登录失效,清除 token,跳转到登录页面
  60.           if (data.code === ResponseCodeEnum.NOLOGIN) {
  61.             store.dispatch(setToken(""));
  62.             window.location.href = "/login";
  63.           }
  64.           return Promise.reject(data);
  65.         }
  66.         return data;
  67.       },
  68.       (error: AxiosError) => {
  69.         fullLoading.hide();
  70.         const { response } = error;
  71.         if (response) {
  72.           checkStatus(response.status);
  73.         }
  74.         return false;
  75.       }
  76.     );
  77.   }
  78.   // 常用请求方法封装
  79.   get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
  80.     return this.service.get(url, { params, ..._object });
  81.   }
  82.   post<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
  83.     return this.service.post(url, params, _object);
  84.   }
  85.   put<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
  86.     return this.service.put(url, params, _object);
  87.   }
  88.   delete<T>(url: string, params?: any, _object = {}): Promise<ResultData<T>> {
  89.     return this.service.delete(url, { params, ..._object });
  90.   }
  91. }
  92. /**
  93. * @description: 校验网络请求状态码
  94. * @param {Number} status
  95. * @return void
  96. */
  97. const checkStatus = (status: number): void => {
  98.   switch (status) {
  99.     case 404:
  100.       message.error("资源不存在!");
  101.       break;
  102.     case 405:
  103.       message.error("请求方式错误!");
  104.       break;
  105.     case 500:
  106.       message.error("服务器异常!");
  107.       break;
  108.     default:
  109.       message.error("请求失败!");
  110.   }
  111. };
  112. const request = new RequestHttp();
  113. export default request;
复制代码
取消哀求的封装:
src/utils/AxiosCancel.ts
  1. import axios, { AxiosRequestConfig, Canceler } from "axios";
  2. const cancelMap = new Map<string, Canceler>();
  3. export class AxiosCancel {
  4.   /**
  5.    * 添加请求的 cancel
  6.    * @param config
  7.    */
  8.   addPending(config: AxiosRequestConfig) {
  9.     const { url, method } = config;
  10.     if (!url || !method) return;
  11.     // 处理同个api,同时多次请求的情况,先移除上一个
  12.     this.removePending(url, method);
  13.     const key = getCancelMapKey(url, method);
  14.     config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
  15.       if (!cancelMap.has(key)) {
  16.         cancelMap.set(key, cancel);
  17.       }
  18.     });
  19.   }
  20.   /**
  21.    * 移除请求
  22.    * @param url
  23.    * @param method
  24.    */
  25.   removePending(url: string | undefined, method: string | undefined) {
  26.     if (!url || !method) return;   
  27.     const key = getCancelMapKey(url, method);
  28.     const cancel = cancelMap.get(key);
  29.     if (cancel) {
  30.       cancel();
  31.       cancelMap.delete(key);
  32.     }
  33.   }
  34.   /**
  35.    * 移除所有请求
  36.    */
  37.   removeAllPending() {
  38.     cancelMap.forEach((cancel) => {
  39.       cancel && cancel();
  40.     });
  41.     cancelMap.clear();
  42.   }
  43. }
  44. function getCancelMapKey(url: string, method: string) {
  45.   return `${url}_${method}`;
  46. }
复制代码
全局加载loading
src/utils/fullLoading.ts
  1. import ReactDOM from "react-dom/client";
  2. import { Spin } from "antd";
  3. // 当前请求的个数
  4. let reqCount = 0;
  5. // 显示 loading
  6. function show() {
  7.   if (reqCount === 0) {
  8.     const dom = document.createElement("div");
  9.     dom.id = "loading";
  10.     dom.style.position = "fixed";
  11.     dom.style.top = "0";
  12.     dom.style.right = "0";
  13.     dom.style.bottom = "0";
  14.     dom.style.left = "0";
  15.     dom.style.background = "rgba(0, 0, 0, 0.5)";
  16.     dom.style.display = "flex";
  17.     dom.style.justifyContent = "center";
  18.     dom.style.alignItems = "center";
  19.     dom.style.zIndex = "9999";
  20.     document.body.appendChild(dom);
  21.     ReactDOM.createRoot(dom).render(<Spin size="large"></Spin>);
  22.   }
  23.   reqCount++;
  24. }
  25. // 隐藏 loading
  26. function hide() {
  27.   reqCount--;
  28.   if (reqCount === 0) {
  29.     const dom = document.getElementById("loading");
  30.     if (dom) {
  31.       document.body.removeChild(dom as HTMLElement);
  32.     }
  33.   }
  34. }
  35. const fullLoading = {
  36.   show,
  37.   hide,
  38. };
  39. export default fullLoading;
复制代码
src/enums/httpEnum.ts
  1. /**
  2. * @description:响应结果枚举
  3. */
  4. export enum ResponseCodeEnum {
  5.         SUCCESS = 200,
  6.         ERROR = 500,
  7.         NOLOGIN = 499,
  8. }
复制代码
类型文件
src/api/type/api.type.ts
  1. // 接口返回结构,不包含 data
  2. export interface ResponseResult {
  3.   // 状态码
  4.   code: number;
  5.   // 消息
  6.   msg: string;
  7. }
  8. // 完整的接口返回结构
  9. export interface ResultData<T = any> extends ResponseResult {
  10.   // 数据
  11.   data: T;
  12. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

农妇山泉一亩田

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表