ts 简易封装 axios,统一 API

文章目录

    • 为什么要封装
    • 目标
    • 文件结构
    • 封装通用请求方法
    • 获得类型提示
    • http 方法
    • 文件上传
    • 使用示例
      • 实例化
      • post 请求
      • 类型提示
      • 文件上传
    • 总结
    • 完整代码:

为什么要封装

axios 本身已经很好用了,看似多次一举的封装则是为了让 axios 与项目解耦。
比如想要将网络请求换成 fetch,那么只需按之前暴露的 api 重新封装一下 fetch 即可,并不需要改动项目代码。

目标

  1. 统一请求API
  2. 使用接口数据时能有代码提示

文件结构

│  index.ts					# 实例化封装类实例
│
├─http
│      request.ts  			# 封装axios
│
└─moduleslogin.ts				# 业务模块upload.ts

封装通用请求方法

先封装一个通用的方法 request,然后在此基础上封装出 http 方法:

class HttpRequest {private readonly instance: AxiosInstance;constructor(config: AxiosRequestConfig) {this.instance = axios.create(config);}request<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return new Promise<TResStructure>((resolve, reject) => {this.instance.request<any, AxiosResponse<TResStructure>>(config).then(res => {// 返回接口数据resolve(res?.data);}).catch(err => reject(err));});}
}

获得类型提示

我希望在使用请求方法时,可以得到后端接口请求参数的提示,并且希望在使用响应结果时,也能得到类型提示。

因此设计了三个泛型:

  1. TReqBodyData:请求体类型
  2. TResStructure:接口响应结构类型
    1. TResData:接口响应 data 字段数据类型

并提供了一个默认的响应结构。使用时可以根据需要改成项目中通用的接口规则。当然在具体方法上也支持自定义响应接口结构,以适应一些不符合通用接口规则的接口。

/** 默认接口返回结构 */
export interface ResStructure<TResData = any> {code: number;data: TResData;msg?: string;
}

http 方法

由 request 方法封装出 http 方法同名的 api。

get<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config?: AxiosRequestConfig<TReqBodyData>
): Promise<TResStructure> {return this.request({ ...config, method: "GET" });
}post<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config: AxiosRequestConfig<TReqBodyData>
): Promise<TResStructure> {return this.request({ ...config, method: "POST" });
}
...

文件上传

文件上传一般使用 formdata,我们也可以简易封装一下。

uploadFile 方法接收 4 个参数:

  1. axios config 对象
  2. 表单内容
    1. 文件对象
    2. 文件对象的表单字段名
    3. hash
    4. 文件名
    5. 更多的表单数据(可通过泛型 TOtherFormData 指定类型)
  3. 上传进度回调
  4. 取消上传的 signal
export interface UploadFileParams<TOtherFormData = Record<string, any>>  {file: File | Blob;  // 文件对象fileHash?: string;  // hashfilename?: string;  // 文件名filed?: string;     // formdata 中文件对象的字段formData?: TOtherFormData; // 文件其他的参数(对象 key-value 将作为表单数据)
}/*** 文件上传* @param {AxiosRequestConfig} config axios 请求配置对象* @param {UploadFileParams} params 待上传文件及其一些参数* @param {(event: AxiosProgressEvent) => void} uploadProgress 上传进度的回调函数* @param {AbortSignal}cancelSignal 取消axios请求的 signal* @returns*/uploadFile<TOtherFormData>(config: AxiosRequestConfig,params: UploadFileParams<TOtherFormData>,uploadProgress?: (event: AxiosProgressEvent) => void,cancelSignal?: AbortSignal) {const formData = new window.FormData();// 设置默认文件表单字段为 fileconst customFilename = params.filed ?? "file";// 是否指定文件名,没有就用文件本来的名字if (params.filename) {formData.append(customFilename, params.file, params.filename);formData.append("filename", params.filename);} else {formData.append(customFilename, params.file);}// 添加文件 hashif (params.fileHash) {formData.append("fileHash", params.fileHash);}// 是否有文件的额外信息补充进表单if (params.formData) {Object.keys(params.formData).forEach(key => {const value = params.formData![key as keyof TOtherFormData];if (Array.isArray(value)) {value.forEach(item => {formData.append(`${key}[]`, item);});return;}formData.append(key, value as any);});}return this.instance.request({...config,method: "POST",timeout: 60 * 60 * 1000, // 60分钟data: formData,onUploadProgress: uploadProgress,signal: cancelSignal,headers: {"Content-type": "multipart/form-data;charset=UTF-8"}});}

使用示例

实例化

import HttpRequest from "./request";/** 实例化 */
const httpRequest = new HttpRequest({baseURL: "http://localhost:8080",timeout: 10000
});

post 请求

/** post 请求 */// 定义请求体类型
interface ReqBodyData {user: string;age: number;
}// 定义接口响应中 data 字段的类型
interface ResDataPost {token: string;
}export function postReq(data: ReqBodyData) {return httpRequest.post<ReqBodyData, ResDataPost>({url: "/__api/mock/post_test",data: data});
}
/** 发起请求 */
async function handleClickPost() {const res = await postReq({ user: "ikun", age: 18 });console.log(res);
}

类型提示

获得使用请求方法时的请求接口参数类型提示:

获得请求接口时的参数类型提示

获得接口默认响应结构的提示:

获得接口默认响应结构的提示

  • 如果个别方法响应结构特殊,则可传入第三个泛型,自定义当前方法的响应结构
// 响应结构
interface ResStructure {code: number;list: string[];type: string;time: number;
}
function postReq(data: ReqBodyData) {return httpRequest.post<ReqBodyData, any, ResStructure>({url: "/__api/mock/post_test",data: data});
}

当前方法自定义接口响应结构:

自定义响应结构

获得接口响应中 data 字段的提示:

获得接口响应中 data 字段的提示

文件上传

/*** 文件上传*/interface OtherFormData {fileSize: number;
}function uploadFileReq(fileInfo: UploadFileParams<OtherFormData>,onUploadProgress?: (event: AxiosProgressEvent) => void,signal?: AbortSignal
) {return httpRequest.uploadFile<OtherFormData>({baseURL: import.meta.env.VITE_APP_UPLOAD_BASE_URL,url: "/upload"},fileInfo,onUploadProgress,signal);
}
// 发起请求const controller = new AbortController();async function handleClickUploadFile() {const file = new File(["hello"], "hello.txt", { type: "text/plain" });const res = await uploadFileReq({ file, fileHash: "xxxx", filename: "hello.txt", formData: { fileSize: 1024 } },event => console.log(event.loaded),controller.signal);console.log(res);
}

总结

  1. 在通用请求方法 request 基础上封装了同名的 http 方法
  2. 使用泛型可获得请求参数和请求结果的类型提示
  3. 额外封装了文件上传的方法

完整代码:

import axios, { AxiosInstance, AxiosProgressEvent, AxiosRequestConfig, AxiosResponse } from "axios";export interface UploadFileParams<TOtherFormData = Record<string, any>> {file: File | Blob;fileHash?: string;filename?: string;filed?: string;formData?: TOtherFormData; // 文件其他的参数(对象 key-value 将作为表单数据)
}/** 默认接口返回结构 */
export interface ResStructure<TResData = any> {code: number;data: TResData;msg?: string;
}/*** A wrapper class for making HTTP requests using Axios.* @class HttpRequest* @example* // Usage example:* const httpRequest = new HttpRequest({baseURL: 'http://localhost:8888'});* httpRequest.get<TReqBodyData, TResData, TResStructure>({ url: '/users/1' })*   .then(response => {*     console.log(response.name); // logs the name of the user*   })*   .catch(error => {*     console.error(error);*   });** @property {AxiosInstance} instance - The Axios instance used for making requests.*/
class HttpRequest {private readonly instance: AxiosInstance;constructor(config: AxiosRequestConfig) {this.instance = axios.create(config);}/*** Sends a request and returns a Promise that resolves with the response data.* @template TReqBodyData - The type of the request body.* @template TResData - The type of the `data` field in the `{code, data}` response structure.* @template TResStructure - The type of the response structure. The default is `{code, data, msg}`.* @param {AxiosRequestConfig} [config] - The custom configuration for the request.* @returns {Promise<TResStructure>} - A Promise that resolves with the response data.* @throws {Error} - If the request fails.** @example* // Sends a GET request and expects a response with a JSON object.* const response = await request<any, {name: string}>({*   method: 'GET',*   url: '/users/1',* });* console.log(response.name); // logs the name of the user*/request<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return new Promise<TResStructure>((resolve, reject) => {this.instance.request<any, AxiosResponse<TResStructure>>(config).then(res => {// 返回接口数据resolve(res?.data);}).catch(err => reject(err));});}/*** 发送 GET 请求* @template TReqBodyData 请求体数据类型* @template TResData 接口响应 data 字段数据类型* @template TResStructure 接口响应结构,默认为 {code, data, msg}* @param {AxiosRequestConfig} config 请求配置* @returns {Promise} 接口响应结果*/get<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config?: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return this.request({ ...config, method: "GET" });}/*** 发送 post 请求* @template TReqBodyData 请求体数据类型* @template TResData 接口响应 data 字段数据类型* @template TResStructure 接口响应结构,默认为 {code, data, msg}* @param {AxiosRequestConfig} config 请求配置* @returns {Promise} 接口响应结果*/post<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return this.request({ ...config, method: "POST" });}patch<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return this.request({ ...config, method: "PATCH" });}delete<TReqBodyData, TResData, TResStructure = ResStructure<TResData>>(config?: AxiosRequestConfig<TReqBodyData>): Promise<TResStructure> {return this.request({ ...config, method: "DELETE" });}/*** 获取当前 axios 实例*/getInstance(): AxiosInstance {return this.instance;}/*** 文件上传* @param {AxiosRequestConfig} config axios 请求配置对象* @param {UploadFileParams} params 待上传文件及其一些参数* @param {(event: AxiosProgressEvent) => void} uploadProgress 上传进度的回调函数* @param {AbortSignal}cancelSignal 取消axios请求的 signal* @returns*/uploadFile<TOtherFormData = any>(config: AxiosRequestConfig,params: UploadFileParams<TOtherFormData>,uploadProgress?: (event: AxiosProgressEvent) => void,cancelSignal?: AbortSignal) {const formData = new window.FormData();// 设置默认文件表单字段为 fileconst customFilename = params.filed || "file";// 是否指定文件名,没有就用文件本来的名字if (params.filename) {formData.append(customFilename, params.file, params.filename);formData.append("filename", params.filename);} else {formData.append(customFilename, params.file);}// 添加文件 hashif (params.fileHash) {formData.append("fileHash", params.fileHash);}// 是否有文件的额外信息补充进表单if (params.formData) {Object.keys(params.formData).forEach(key => {const value = params.formData![key as keyof TOtherFormData];if (Array.isArray(value)) {value.forEach(item => {// 对象属性值为数组时,表单字段加一个[]formData.append(`${key}[]`, item);});return;}formData.append(key, value as any);});}return this.instance.request({...config,method: "POST",timeout: 60 * 60 * 1000, // 60分钟data: formData,onUploadProgress: uploadProgress,signal: cancelSignal,headers: {"Content-type": "multipart/form-data;charset=UTF-8"}});}
}export default HttpRequest;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/129044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频增强和修复工具 Topaz Video AI mac中文版功能

Topaz Video AI mac是一款使用人工智能技术对视频进行增强和修复的软件。它可以自动降噪、去除锐化、减少压缩失真、提高清晰度等等。Topaz Video AI可以处理各种类型的视频&#xff0c;包括低分辨率视频、老旧影片、手机录制的视频等。 使用Topaz Video AI非常简单&#xff0c…

突破防火墙的一种方法

当Linux防火墙阻止来自某个ip的数据时&#xff0c;它应该是根据ip数据报里“源IP地址”字段取得的对方ip吧&#xff0c;那对方就不能通过篡改“源IP地址”来绕过防火墙吗&#xff1f;NAT模式下的路由器就修改了这个字段。 但这样的话&#xff0c;攻击者是收不到服务器返回的数…

学 Java 怎么进外企?

作者&#xff1a;**苍何&#xff0c;CSDN 2023 年 实力新星&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#…

麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器

原文链接&#xff1a;麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟桌面操作系统软件仓库搭建的文章01-新创建软件仓库服务器&#xff0c;本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上搭建内网…

docker 下安装mysql8.0

在docker中查询mysql镜像 PS C:\Users\admin> docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation……

【Python_GraphicsView 学习笔记(一)】Graphics View框架的基本介绍

【Python_GraphicsView 学习笔记&#xff08;一&#xff09;】Graphics View框架的基本介绍 前言正文1、Graphics View框架简介2、Graphics View框架与QPainter类的区别3、Graphics View框架的三个组成部分4、场景QGraphicsScene类5、视图QGraphicsView类6、图形项QGraphicsIte…

深度学习_3 数据操作之线代,微分

线代基础 标量 只有一个元素的张量。可以通过 x torch.tensor(3.0) 方式创建。 向量 由多个标量组成的列表&#xff08;一维张量&#xff09;。比如 x torch.arange(4) 就是创建了一个1*4的向量。可以通过下标获取特定元素&#xff08;x[3]&#xff09;&#xff0c;可以通…

Vue3入门指南:零基础小白也能轻松理解的学习笔记

文章目录 创建项目开发环境项目目录模板语法属性绑定条件渲染列表渲染事件处理内联事件处理器方法事件处理器&#xff08;常用&#xff09; 事件参数获取 event 事件事件传参 事件修饰符阻止默认事件阻止事件冒泡 数组变化侦测变更方法替换一个数组 计算属性class 绑定单对象绑…

野火霸天虎 STM32F407 学习笔记_1 stm32介绍;调试方法介绍

STM32入门——基于野火 F407 霸天虎课程学习 前言 博主开始探索嵌入式以来&#xff0c;其实很早就开始玩 stm32 了。但是学了一段时间之后总是感觉还是很没有头绪&#xff0c;不知道在学什么。前前后后分别尝试了江协科技、正点原子、野火霸天虎三次 stm32 的课程学习。江协科…

多模态 多引擎 超融合 新生态!2023亚信科技AntDB数据库8.0产品发布

9月20日&#xff0c;以“多模态 多引擎 超融合 新生态”为主题的亚信科技AntDB数据库8.0产品发布会成功举办&#xff0c;从技术和生态两个角度全方位展示了AntDB数据库第8次大型能力升级和生态建设成果。浙江移动、用友、麒麟软件、华录高诚、金云智联等行业伙伴及业界专家共同…

如何做好网页配色,分享一些配色方案和方法

很多网页设计师在选择网页配色方案时&#xff0c;会纠结于用什么网页UI配色方案来吸引客户的注意力&#xff0c;传达信息。选择正确的颜色是网页设计不可或缺的一部分。本指南将从色彩理论和色彩心理学入手&#xff0c;分享三个网页UI配色的简单步骤。 网页UI配色方法有很多&a…

关于msvcp120.dll丢失的解决方法详解,快速解决dll丢失问题

在计算机使用过程中&#xff0c;经常会遇到“msvcp120.dll丢失”的错误提示。这个错误提示通常出现在运行某些程序或游戏时&#xff0c;造成相关应用程序可能无法正常启动或运行。那么&#xff0c;究竟是什么原因导致了msvcp120.dll文件的丢失呢&#xff1f;本文将详细解析msvc…

在 Linux 中更改 echo 的输出颜色

文章目录 前言一、快速入门二、基本使用2.1 对于常规的输出2.2 对于字体加粗的输出2.3 对于字体斜体的输出2.4 对于带下划线的输出2.5 对于闪烁效果的输出 三、小结 前言 在计算机编程世界中&#xff0c;颜色不仅仅是一种视觉效果&#xff0c;它也是一种信息传递的工具。特别是…

Doris:StreamLoad导入数据

目录 1.基本原理 2.支持数据格式 3.StreamLoad语法 3.1.请求参数 3.2.返回参数 4.StreamLoad实践 4.1.使用 curl命令 4.2.使用Java代码 Stream load 是一个同步的导入方式&#xff0c;用户通过发送 HTTP 协议发送请求将本地文件或数据流导入到 Doris 中。Stream load 主…

免费记课时小程序-全优学堂

1. 教师使用小程序记上课 使用步骤 创建了员工账号&#xff0c;员工需设置为教师为班级进行排课使用系统账号绑定小程序&#xff0c;记上课 #1.1 创建员工账号 通过系统菜单’机构设置->员工管理‘&#xff0c;添加本机构教师及其他员工。 添加过程中&#xff0c;可设置…

ffmpeg mp3截取命令,视频与mp3合成带音频视频命令

从00:00:03.500开始截取往后长度到结尾的mp3音频&#xff08;这个更有用&#xff0c;测试好用&#xff09; ffmpeg -i d:/c.mp3 -ss 00:00:03.500 d:/output.mp3 将两个音频合并成一个音频&#xff08;测试好用&#xff09; ffmpeg -i "concat:d:/c.mp3|d:/output.mp3&…

CSS3设计动画样式

CSS3动画包括过渡动画和关键帧动画&#xff0c;它们主要通过改变CSS属性值来模拟实现。我将详细介绍Transform、Transitions和Animations 3大功能模块&#xff0c;其中Transform实现对网页对象的变形操作&#xff0c;Transitions实现CSS属性过渡变化&#xff0c;Animations实现…

Git复制代码

目录 一、常用下载代码 1.登录Git克隆SSH​编辑 2.新建文件然后右键点击Git Bash Here 3.git clone Paste 二. 本地下载 1.从本地进入页面 2.生成代码——>导入——>生成代码后下载 3.解压道相应位置 一、常用下载代码 1.登录Git克隆SSH 2.新建文件然后右键点击…

C# list<T>去重

文章目录 C# list<T>去重值类型去重List<object>object is intobject is decimalobject is charobject is boolobject is string List<int>List<string> 引用类型去重 C# list去重 值类型去重 List object is int //object is intList<object&g…

图像二值化阈值调整——cv2.threshold方法

二值化阈值调整&#xff1a;调整是指在进行图像二值化处理时&#xff0c;调整阈值的过程。阈值决定了将图像中的像素分为黑色和白色的界限&#xff0c;大于阈值的像素被设置为白色&#xff0c;小于等于阈值的像素被设置为黑色。 首先画出灰度直方图&#xff1a;横坐标是灰度值…