关于前端开发中常用的 axios 封装
jcLee95 的个人博客:https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
本文地址:https://blog.csdn.net/qq_28550263/article/details/131099244
目 录
相关文章:[《flutter 中的 dio 模块用法解析与二次封装》](https://blog.csdn.net/qq_28550263/article/details/131152631](https://blog.csdn.net/qq_28550263/article/details/131152631)
1. 概述
1.1 什么是 axios
Axios 是一个基于 Promise 的 HTTP 客户端,用于在浏览器和 Node.js 中发送异步请求。它是一个流行的 JavaScript 库,旨在简化客户端端与服务器端之间的数据传输过程。Axios 提供了一个简洁而强大的 API,可以轻松地执行各种 HTTP 请求,例如 GET、POST、PUT、DELETE 等。
Axios 具有以下特点和功能:
功能特点 | 描述 |
支持 Promise | Axios 基于 Promise,可以利用 Promise 的优点,如链式调用、错误处理和异步操作。 |
跨浏览器支持 | Axios 可在浏览器和 Node.js 环境中使用,提供了一致的 API。 |
自动转换数据 | Axios 可以自动将请求和响应数据转换为不同的格式,如 JSON、XML、FormData 等。 |
拦截器 | Axios 提供了请求和响应拦截器,可以在请求发送之前和响应返回之后进行拦截和处理。 |
取消请求 | Axios 支持取消请求的功能,可以在需要时中止正在进行的请求。 |
错误处理 | Axios 提供了全局的错误处理机制,可以方便地捕获和处理请求过程中的错误。 |
防止 CSRF | Axios 可以通过设置请求头或者使用 CSRF 令牌来防止跨站请求伪造。 |
Axios 是一个功能强大、易于使用且广泛采用的 HTTP 客户端库,可以帮助开发者轻松地与服务器进行数据交互。无论是处理简单的 API 请求还是处理复杂的网络通信,Axios 提供了一套简洁而灵活的工具来满足各种需求。读者可以在以下博文阅览axios中文翻译文档:《axios 文档中文翻译》,地址:https://blog.csdn.net/qq_28550263/article/details/122537980
1.2 关于本文
2. 从 axios 的基本用法开始
2.1 axios 用法简介
2.1.1 安装和引入 axios 模块
npminstallaxios# oryarnaddaxios# orpnpmiaxios
安装完成后你就可以如下引入axios:
importaxiosfrom'axios';
2.1.2 发送GET请求
axios.get('/api/data') .then((response) => { // 处理成功响应console.log(response.data); }) .catch((error) => { // 处理错误响应console.error(error); });
2.1.3 发送POST请求
axios.post('/api/data', { /* 数据 */ }) .then((response) => { // 处理成功响应 console.log(response.data); }) .catch((error) => { // 处理错误响应 console.error(error); });
2.2 为什么需要封装axios
尽管可以直接使用axios进行基本的请求,但未封装axios存在以下不便之处:
- 代码冗余:在每个请求中都需要重复编写请求配置、错误处理等逻辑,导致代码冗余和可读性降低。
- 配置不一致:如果项目中有多个地方使用axios,每个地方的配置可能不一致,导致代码风格不统一。
- 缺乏拦截器:未封装的axios没有预定义的请求和响应拦截器,无法方便地统一处理请求和响应的逻辑,如认证、错误处理等。
- API管理困难:未封装的axios无法方便地管理API接口,容易导致接口定义分散,不易查找和修改。
- 可扩展性受限:未封装的axios难以进行功能扩展,如添加自定义拦截器、缓存等功能。
综上所述,封装axios可以解决未封装axios的不便之处,提供更好的代码组织、可维护性和可扩展性。通过封装,可以统一配置、提供拦截器处理、方便API管理,并且使代码更加简洁、可读和易于维护。总结起来,封装axios有以下几个原因:
- 代码复用:通过封装,可以将通用的请求逻辑封装成可重用的函数或模块,减少重复代码的编写。
- 可维护性:将axios的配置、拦截器等逻辑封装在一处,方便维护和修改。
- 错误处理:封装可以集中处理请求和响应的错误,提供统一的错误处理机制。
- 接口统一管理:将API接口的定义和管理集中在一处,方便查找和修改。
- 方便扩展:通过封装,可以轻松地扩展axios的功能,比如添加认证、缓存等功能。
3. axios 的封装
当封装axios时,可以采用不同的形式。下面分别介绍函数封装、实例封装和类封装,并给出使用TypeScript编写的具体封装示例代码:
3.1 函数封装方式
函数封装是将常用的请求封装成函数,接收参数并返回Promise对象。
importaxios, { AxiosRequestConfig, AxiosResponse } from'axios'; /** * 发送GET请求 * @param url 请求URL * @param params 请求参数 * @returns Promise对象,包含响应数据 */exportfunctionget(url: string, params?: AxiosRequestConfig['params']): Promise<AxiosResponse> { returnaxios.get(url, { params }); } /** * 发送POST请求 * @param url 请求URL * @param data 请求数据 * @returns Promise对象,包含响应数据 */exportfunctionpost(url: string, data?: any): Promise<AxiosResponse> { returnaxios.post(url, data); } // 在Vue组件中使用import { get, post } from'@/api'; exportdefault { methods: { fetchData() { get('/data') .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, postData() { post('/data', { /* 数据 */ }) .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, }, };
3.2 实例封装方式
实例封装是创建axios实例,并设置通用的配置、拦截器等。
importaxios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from'axios'; classApiClient { privateinstance: AxiosInstance; constructor(baseURL: string) { this.instance=axios.create({ baseURL, timeout: 5000, }); // 请求拦截器this.instance.interceptors.request.use( (config) => { // 在请求发送前做一些处理returnconfig; }, (error) => { // 处理请求错误returnPromise.reject(error); } ); // 响应拦截器this.instance.interceptors.response.use( (response) => { // 对响应数据进行处理returnresponse.data; }, (error) => { // 处理响应错误returnPromise.reject(error); } ); } /** * 发送GET请求 * @param url 请求URL * @param params 请求参数 * @returns Promise对象,包含响应数据 */publicget(url: string, params?: AxiosRequestConfig['params']): Promise<AxiosResponse> { returnthis.instance.get(url, { params }); } /** * 发送POST请求 * @param url 请求URL * @param data 请求数据 * @returns Promise对象,包含响应数据 */publicpost(url: string, data?: any): Promise<AxiosResponse> { returnthis.instance.post(url, data); } } // 在Vue组件中使用importApiClientfrom'@/api'; constapi=newApiClient('https://api.example.com');exportdefault { methods: { fetchData() { api.get('/data') .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, postData() { api.post('/data', { /* 数据 */ }) .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, }, };
3.3 类封装方式
类封装通过类来封装axios,封装各种请求方法和处理逻辑。例如:
importaxios, { AxiosRequestConfig, AxiosResponse } from'axios'; classApiClient { privatebaseURL: string; privateinstance=axios.create({ timeout: 5000, }); constructor(baseURL: string) { this.baseURL=baseURL; // 请求拦截器this.instance.interceptors.request.use( (config) => { // 在请求发送前做一些处理returnconfig; }, (error) => { // 处理请求错误returnPromise.reject(error); } ); // 响应拦截器this.instance.interceptors.response.use( (response) => { // 对响应数据进行处理returnresponse.data; }, (error) => { // 处理响应错误returnPromise.reject(error); } ); } /** * 发送GET请求 * @param url 请求URL * @param params 请求参数 * @returns Promise对象,包含响应数据 */publicget(url: string, params?: AxiosRequestConfig['params']): Promise<AxiosResponse> { returnthis.instance.get(this.baseURL+url, { params }); } /** * 发送POST请求 * @param url 请求URL * @param data 请求数据 * @returns Promise对象,包含响应数据 */publicpost(url: string, data?: any): Promise<AxiosResponse> { returnthis.instance.post(this.baseURL+url, data); } } // 在Vue组件中使用importApiClientfrom'@/api'; constapi=newApiClient('https://api.xxxxxx.com'); exportdefault { methods: { fetchData() { api.get('/data') .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, postData() { api.post('/data', { /* 数据 */ }) .then((response) => { // 处理成功响应 }) .catch((error) => { // 处理错误响应 }); }, }, };
3.4 三种封装方式的比较
上面我们介绍了通过 函数封装、实例封装、类封装 三种封装方式来封装 axios。当然,它们都可以用来封装axios,它们在代码组织和使用上有一些区别。本节我们对这三种方式做一些比较。
封装方式 | 描述 |
函数封装方式 | 函数封装方式是最简单的封装方式,它将 axios 作为函数的参数传入,并在函数内部执行相应的请求。 这种方式适用于简单的请求场景,可以快速地发送请求并获取响应。 函数封装方式的主要优点是简单易用,没有额外的复杂性,适合于小型项目或者只有少量API请求的情况。然而,函数封装方式的可扩展性相对较差,难以处理复杂的请求逻辑和统一的错误处理。 |
实例封装方式 | 实例封装方式创建了一个axios实例,并通过给实例添加方法来封装不同类型的请求。 这种方式可以在一个实例中设置通用的请求配置,例如基础URL、拦截器等。 实例封装方式具有更好的可扩展性和灵活性,可以根据需要定义多个实例,每个实例可以有自己的配置。这种方式适用于中大型项目,可以更好地组织和管理请求代码。 |
类封装方式 | 类封装方式使用面向对象的思想,将axios封装成一个类,并通过类的方法来发送请求。 这种方式结合了函数封装和实例封装的优点,提供了更强大的封装能力和更好的代码组织结构。 类封装方式可以定义公共的请求配置和错误处理逻辑,并可以通过继承和多态的方式实现更高级的功能扩展。它适用于大型项目和需要复杂请求逻辑的场景。 |
总的来说,函数封装方式简单易用,实例封装方式具有一定的可扩展性和灵活性,而类封装方式则提供了最强大的封装能力和代码组织结构。实际开发中具体选择哪种方式可以取决于项目的规模、复杂性,但是一般更多地会取决于团队的开发经验,以及个人的偏好和需求。
4. 弃用 Axios 的思考
4.1 Axios 存在的主要问题
xios是一个常用的JavaScript库,用于在浏览器和Node.js中进行HTTP请求。尽管Axios是一个流行的选择,但它也有一些不足之处:
项目 | 描述 | 替代方向 |
体积较大 | Axios的体积相对较大,这可能在某些情况下对性能产生一些负面影响。 | 如果项目对文件大小有较严格的要求,可以考虑使用一些轻量级的替代方案。 |
API 设计风格 | Axios的API设计是基于Promise的,这对于处理异步请求非常方便。然而,一些开发者可能更喜欢使用基于回调的API或者async/await语法。 | 根据个人喜好和项目需求,选择适合的API风格可能更合适。 |
浏览器兼容性 | 尽管Axios在大多数现代浏览器中运行良好,但在某些旧版本的浏览器中可能存在兼容性问题。 | 如果你需要支持较旧的浏览器,可能需要考虑使用其他解决方案或者进行额外的兼容性处理。 |
4.2 一些现成的可选替代方案
替代方案收集中,欢迎在评论区留言推荐
方案 | 描述 | 文档链接 |
Fetch API | Fetch API 是现代浏览器原生提供的一种用于发起网络请求的接口,它支持Promise和async/await语法。它具有较小的体积,且在大多数现代浏览器中都有良好的兼容性。 | https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API |
Superagent | Superagent 是另一个流行的HTTP请求库,它具有简洁的API设计和较小的体积。它支持回调和Promise两种风格,并且在浏览器和Node.js中都能运行。 | https://ladjs.github.io/superagent/docs/zh_CN/index.html |
Fetch+AbortController | 如果你只关注现代浏览器的兼容性,你可以结合使用Fetch API和AbortController来发起请求并支持请求的取消。AbortController允许你在需要时取消正在进行的请求,这在某些情况下非常有用。 | https://developer.mozilla.org/zh-CN/docs/Web/API/AbortController |
5. Fetch
5.1 Fetch 简介
5.1.1 什么是 Fetch
在过去,前端开发人员通常使用XMLHttpRequest对象来进行网络请求。然而,XMLHttpRequest存在一些问题,比如使用繁琐的接口、不统一的语法和难以处理错误。为了解决这些问题,W3C(World Wide Web Consortium)和Web开发社区共同努力,开发了Fetch API。Fetch是一种现代的Web API,用于在前端中进行网络请求。它提供了一种替代传统XMLHttpRequest(XHR)的方式,以更简单、灵活和统一的方式处理网络通信。Fetch API的设计目标包括:
- 提供一种简单而强大的方式来进行网络请求。
- 统一网络请求的接口和语法,使开发人员更容易理解和使用。
- 支持Promise对象,以便更好地处理异步请求。
- 提供更灵活的请求和响应处理选项。
5.1.2 Fetch与传统方式的比较
对比使用 XMLHttpRequest
与 XMLHttpRequest 方式相比。Fetch API相对于XMLHttpRequest具有以下优势:
项目 | 描述 |
更简洁的语法 | Fetch API使用Promise和链式调用的方式,使代码更易读和组织。 |
内置的JSON解析 | Fetch API内置了将响应数据解析为JSON的方法,不需要手动解析。 |
支持流数据 | Fetch API可以处理流数据,而XMLHttpRequest不支持。 |
更灵活的请求选项 | Fetch API提供了更丰富的请求选项,如headers、mode、cache等。 |
更好的错误处理 | Fetch API使用Promise的catch方法来处理错误,比传统方式更直观。 |
对比使用 axios 模块
与 axios 的比较第三方模块对比:
对比项 | 描述 |
API设计 | Fetch API的API设计更现代化和简洁,使用Promise和链式调用。而axios使用传统的回调函数方式设计API。 |
兼容性 | Fetch API在现代浏览器中有良好的支持,但在老旧浏览器中存在兼容性问题。而axios通过封装XMLHttpRequest对象,具有更好的兼容性。 |
功能扩展 | axios提供了一些额外的功能,如请求取消、拦截器、请求重试等,而Fetch API没有内置这些功能,需要开发人员自行实现。 |
请求转换 | axios支持请求和响应的数据转换,可以自动将请求和响应数据转换为JSON、FormData等格式。Fetch API需要手动处理数据转换。 |
浏览器环境外支持 | axios可以在浏览器和Node.js环境中使用,而Fetch API主要用于浏览器环境。 |
选择使用Fetch API还是axios取决于具体需求和项目要求。如果希望使用原生的浏览器API并且在现代浏览器中运行,可以考虑使用 Fetch API。如果需要更多的功能扩展、兼容性和数据转换支持,尚且还可以继续使用 axios。
5.1 Fetch 用法
5.2.1 快速入门
使用 Fetch API可以轻松地发起各种类型的HTTP请求并处理响应数据,本节给一个基本的Fetch请求示例:
fetch('https://api.xxxxxx.com/data') .then((response: Response) => { if (!response.ok) { throw new Error('网络响应不正常'); } return response.json(); }) .then((data: any) => { console.log(data); }) .catch((error: Error) => { console.error('Error:', error); });
这个例子中,我们使用 fetch 函数发起了一个 GET 请求,并指定了要请求的 URL。然后,我们使用 Promise 的 then 方法处理响应。如果响应的状态码 不是200 时我们抛出一个错误。否则,我们将响应数据解析为 JSON 格式并输出到控制台。
5.2.2 Fetch的请求选项
Fetch API提供了一些可选的请求选项,用于自定义请求的行为。以下是一些常用的选项:
选项 | 描述 |
method |
指定请求的 HTTP 方法,如 GET、POST、PUT、DELETE 等 |
headers |
设置请求的头部信息,如 Content-Type 、Authorization 等 |
body |
设置请求的主体数据,可以是字符串、FormData对象等 |
mode |
设置请求的模式,如 cors 、no-cors 、same-origin 等 |
cache |
设置请求的缓存模式,如 default 、no-store 、reload 等 |
例如:
const options: RequestInit = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token' }, body: JSON.stringify({ username: 'john', password: 'secret' }) }; fetch('https://api.example.com/login', options) .then((response: Response) => { if (!response.ok) { throw new Error('网络响应不正常'); } return response.json(); }) .then((data: any) => { console.log(data); }) .catch((error: Error) => { console.error('Error:', error); });
【注】
5.2.3 Fetch 的响应处理
Fetch API提供了多种处理响应的方法,您可以根据需要选择适合的方法。以下是一些常用的处理方法:
方法 | 描述 |
response.text() |
将响应数据作为文本返回。 |
response.json() |
将响应数据解析为JSON格式返回。 |
response.blob() |
将响应数据解析为Blob对象返回。 |
response.arrayBuffer() |
将响应数据解析为ArrayBuffer对象返回。 |
例如:
fetch('https://api.example.com/image') .then((response: Response) => { if (!response.ok) { throw new Error('网络响应不正常'); } return response.blob(); }) .then((blob: Blob) => { const img = document.createElement('img'); img.src = URL.createObjectURL(blob); document.body.appendChild(img); }) .catch((error: Error) => { console.error('Error:', error); });
本例我们使用 response.blob()
方法将响应数据解析为 Blob对象。然后,我们创建一个img
元素,并将 Blob 对象的 URL 赋值给 img
的 src
属性,以显示图像。