在 Vue3 开发中,网络请求是连接前端与后端的核心环节,而 Axios 作为目前最主流的 HTTP 客户端,凭借其强大的功能和友好的 API 成为了 Vue 开发者的首选工具。本文将基于 Vue3 技术栈,从 Axios 的基础概念出发,逐步深入到实例封装、拦截器、错误处理和并发请求等高阶应用,结合实际案例帮助你彻底掌握 Axios 在 Vue3 项目中的使用技巧。

一、Axios 基础:为什么它是 Vue3 项目的首选?

在开始使用 Axios 前,我们首先要明确:为什么在 Vue3 项目中,Axios 能替代 jQuery-Ajax 和 Fetch API 成为主流选择?

1.1 Axios 是什么?

Axios 是一个基于 Promise 的 HTTP 客户端,既可以在浏览器中创建 XMLHttpRequests,也能在 Node.js 环境中发起 http 请求,本质上是对原生 XHR 的 Promise 化封装,完全符合最新的 ES 规范。它的核心优势在于功能全面且兼容性强,不仅支持 Promise API,还能实现请求 / 响应拦截、数据自动转换、请求取消等实用功能,同时对旧版浏览器也有良好的适配。

1.2 对比其他请求方案:Axios 的优势在哪?

在前端开发中,我们曾有 jQuery-Ajax 和 Fetch API 两种常见的请求方案,但它们在 Vue3 项目中都存在明显短板:

  • jQuery-Ajax:虽然功能强大,但需要引入整个 jQuery 库,而 Vue3 本身专注于视图层,引入冗余库会增加项目体积,得不偿失;
  • Fetch API:作为浏览器内置 API,虽符合 W3C 标准,但默认不携带 Cookie,需要额外配置,且 API 复杂度高于 Axios,对旧版浏览器(如 IE)不兼容。

相比之下,Axios 既没有 jQuery 的体积冗余问题,也解决了 Fetch API 的兼容性和配置繁琐问题,同时还提供了拦截器、实例管理等进阶功能,完美契合 Vue3 项目的开发需求。此外,Vue 官方在 2.0 版本后不再维护 vue-resource,并明确推荐使用 Axios,这也进一步巩固了它的主流地位。

1.3 快速上手:Axios 的安装与基础使用

Axios 的安装非常简单,在 Vue3 工程化项目中,首选通过 npm 或 yarn 安装:

bash

# npm 安装
npm install axios
# yarn 安装
yarn add axios

如果是简单的非工程化页面,也可以通过 CDN 直接引入:

html

预览

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

安装完成后,我们可以在 Vue3 组件中快速实现一个数据请求案例。例如,从公共 API 获取用户信息并展示:

vue

<template>
  <div>
    <h1>用户信息</h1>
    <div v-if="user">
      <p><strong>姓名:</strong> {{ user.name }}</p>
      <p><strong>邮箱:</strong> {{ user.email }}</p>
      <p><strong>电话:</strong> {{ user.phone }}</p>
    </div>
    <div v-else>正在加载用户数据...</div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axios from 'axios';

// 定义用户类型接口
interface User {
  name: string;
  email: string;
  phone: string;
}

// 创建响应式变量存储用户数据
const user = ref<User | null>(null);

// 异步函数:获取用户数据
const fetchUser = async () => {
  try {
    // 发起 GET 请求,通过泛型指定响应数据类型
    const response = await axios.get<User>('https://jsonplaceholder.typicode.com/users/1');
    // Axios 自动解析 JSON 数据,直接从 response.data 获取结果
    user.value = response.data;
  } catch (error) {
    // 错误处理:打印错误信息
    console.error('获取用户数据失败:', error);
  }
};

// 组件挂载后发起请求
onMounted(() => {
  fetchUser();
});
</script>

这个案例中,我们使用了 Vue3 的 Composition API(refonMounted)和 TypeScript 类型定义,结合 Axios 的 get 方法实现了数据请求。需要注意的是,Axios 会自动将服务器返回的 JSON 数据解析到 response.data 中,无需手动处理;同时通过 try...catch 块可以捕获请求过程中的错误,保证页面稳定性。

二、Axios 进阶:实例封装与配置管理

在中小型项目中,直接使用 Axios 发起请求是可行的,但随着项目规模扩大,多个组件重复引入 Axios 会导致代码冗余,且全局配置难以统一。此时,封装 Axios 实例就成为了最佳实践。

2.1 为什么要封装 Axios 实例?

封装 Axios 实例的核心目的是统一配置、减少冗余、便于维护。通过创建自定义实例,我们可以:

  1. 为不同业务模块设置不同的基础 URL(如 “用户模块” 和 “商品模块” 调用不同后端服务);
  2. 统一设置超时时间、请求头、请求参数等配置;
  3. 集中管理拦截器,避免在多个组件中重复编写拦截逻辑;
  4. 降低组件与 Axios 的耦合度,后续若需替换请求库,只需修改封装模块即可。

2.2 实战:封装一个可复用的 Axios 实例

我们在 Vue3 项目的 src/utils 目录下创建 request.js 文件,封装一个基础实例:

javascript

运行

// src/utils/request.js
import axios from 'axios';

// 创建 Axios 实例
const service = axios.create({
  // 基础 URL:所有请求都会自动拼接该前缀(除非请求 URL 是绝对路径)
  baseURL: 'https://jsonplaceholder.typicode.com',
  // 超时时间:5 秒内无响应则中断请求
  timeout: 5000,
  // 默认请求头:可根据需求添加(如 Content-Type)
  headers: {
    'Content-Type': 'application/json'
  }
});

// 导出实例,供其他组件使用
export default service;

封装完成后,在组件中只需导入这个实例,即可发起请求,无需重复配置基础 URL:

vue

<template>
  <div>
    <button @click="fetchPost">获取文章</button>
    <div v-if="post">
      <h3>{{ post.title }}</h3>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';
// 导入封装好的 Axios 实例
import request from '@/utils/request';

const post = ref(null);

// 发起请求:URL 直接使用相对路径,自动拼接 baseURL
const fetchPost = async () => {
  try {
    const response = await request.get('/posts/1');
    post.value = response.data;
  } catch (error) {
    console.error('获取文章失败:', error);
  }
};
</script>

2.3 多实例管理:应对复杂业务场景

在大型项目中,可能需要请求多个不同的后端服务(如 “业务 API” 和 “数据分析 API”),此时可以创建多个 Axios 实例,分别对应不同服务:

javascript

运行

// src/api/business.js:业务模块 API 实例
import axios from 'axios';
const businessApi = axios.create({
  baseURL: 'https://api.business.com/v1',
  timeout: 5000
});
export default businessApi;

// src/api/analytics.js:数据分析模块 API 实例
import axios from 'axios';
const analyticsApi = axios.create({
  baseURL: 'https://api.analytics.com/track',
  timeout: 10000,
  headers: { 'X-Client-ID': 'vue3-project' } // 专属请求头
});
export default analyticsApi;

使用时,根据业务需求导入对应的实例即可,各实例的配置互不干扰,极大提升了代码的可维护性。

三、Axios 核心功能:拦截器与错误处理

Axios 的拦截器是其最强大的功能之一,能够在请求发送前、响应处理前对数据进行统一处理;而完善的错误处理则是保证用户体验的关键。

3.1 拦截器:请求与响应的 “中间件”

拦截器分为请求拦截器响应拦截器,分别作用于请求发送前和响应处理前。

3.1.1 请求拦截器:统一预处理请求

请求拦截器的常见使用场景包括:添加身份验证 Token、显示全局加载动画、格式化请求参数等。例如,在每个请求头中添加 Token 以实现身份验证:

javascript

运行

// 在 request.js 中添加请求拦截器
service.interceptors.request.use(
  (config) => {
    // 从本地存储中获取 Token(实际项目中可存在 Vuex/Pinia 中)
    const token = localStorage.getItem('token');
    // 若 Token 存在,添加到请求头
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    // 返回修改后的配置(必须返回,否则请求会中断)
    return config;
  },
  (error) => {
    // 处理请求发送前的错误(如配置错误)
    console.error('请求拦截器错误:', error);
    return Promise.reject(error);
  }
);
3.1.2 响应拦截器:统一处理响应与错误

响应拦截器可以简化响应数据结构、统一处理错误(如 Token 过期、404 错误)。例如,直接返回响应的核心数据,并对常见错误进行提示:

javascript

运行

// 在 request.js 中添加响应拦截器
service.interceptors.response.use(
  (response) => {
    // 简化数据结构:直接返回 response.data(无需在组件中多次 .data)
    return response.data;
  },
  (error) => {
    // 统一错误处理
    let errorMsg = '';
    if (error.response) {
      // 服务器返回错误状态码(如 401、404、500)
      switch (error.response.status) {
        case 401:
          errorMsg = 'Token 无效,请重新登录';
          // Token 过期:清除本地存储并跳转登录页
          localStorage.removeItem('token');
          window.location.href = '/login';
          break;
        case 404:
          errorMsg = `请求资源不存在:${error.response.config.url}`;
          break;
        case 500:
          errorMsg = '服务器内部错误,请稍后再试';
          break;
        default:
          errorMsg = `请求失败,状态码:${error.response.status}`;
      }
    } else if (error.code === 'ECONNABORTED') {
      // 请求超时
      errorMsg = '请求超时,请检查网络连接';
    } else {
      // 网络错误(如断网)
      errorMsg = '网络连接异常';
    }
    // 显示错误提示(实际项目中可使用 Element Plus 等 UI 库的 Message 组件)
    alert(errorMsg);
    // 继续抛出错误,供组件内的 catch 处理(可选)
    return Promise.reject(error);
  }
);

添加拦截器后,组件中的请求逻辑会变得更简洁。例如,获取文章数据时无需再处理 response.data,也无需重复编写错误提示:

javascript

运行

const fetchPost = async () => {
  try {
    // 拦截器已简化数据,直接获取结果
    const post = await request.get('/posts/1');
    post.value = post;
  } catch (error) {
    // 拦截器已处理错误提示,此处可根据业务需求补充逻辑
    console.error('组件内错误处理:', error);
  }
};

3.2 错误处理:覆盖所有异常场景

Axios 的错误主要分为四类,在响应拦截器中需要全面覆盖:

  1. 网络错误:断网、DNS 解析失败等,此时 error.response 为 undefined
  2. 请求超时:超过配置的 timeout 时间,error.code 为 ECONNABORTED
  3. 服务器错误:返回非 2xx 状态码(如 401、404、500),错误信息在 error.response 中;
  4. 请求取消:主动取消请求(如用户点击 “取消” 按钮),可通过 axios.isCancel(error) 判断。

通过上文的响应拦截器,我们已经覆盖了前三种常见错误,而请求取消则需要结合 axios.CancelToken 实现(Vue3 项目中可使用 AbortController 替代,更符合标准)。

四、Axios 高级应用:并发请求与性能优化

在页面初始化时,若需要同时获取多个接口的数据(如 “用户信息”“文章列表”“相册列表”),使用并发请求可以大幅减少加载时间,提升用户体验。

4.1 并发请求的实现:axios.all 与 Promise.all

Axios 提供 axios.all 方法用于处理并发请求,它接收一个 Promise 数组作为参数,当所有请求都成功后,返回一个包含所有响应结果的数组。同时,axios.spread 可以将结果数组 “展开” 为独立参数,便于处理。

例如,同时获取用户信息、文章列表和相册列表:

vue

<script setup>
import { ref } from 'vue';
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://jsonplaceholder.typicode.com'
});

// 定义三个请求函数,均返回 Promise
const getUser = () => api.get('/users/1');
const getPosts = () => api.get('/posts', { params: { userId: 1 } });
const getAlbums = () => api.get('/albums', { params: { userId: 1 } });

// 响应式变量存储数据
const user = ref(null);
const posts = ref(null);
const albums = ref(null);
const loading = ref(false);

// 并发请求函数
const fetchAllData = () => {
  loading.value = true;
  // 使用 axios.all 发起并发请求
  axios.all([getUser(), getPosts(), getAlbums()])
    .then(axios.spread((userRes, postsRes, albumsRes) => {
      // 展开结果,分别赋值
      user.value = userRes.data;
      posts.value = postsRes.data;
      albums.value = albumsRes.data;
    }))
    .catch(error => {
      console.error('并发请求失败:', error);
      alert('数据加载失败');
    })
    .finally(() => {
      // 无论成功与否,关闭加载状态
      loading.value = false;
    });
};
</script>

在现代 JavaScript 中,更推荐使用 Promise.all 配合 async/await 语法,代码更简洁易读:

javascript

运行

const fetchAllDataAsync = async () => {
  loading.value = true;
  try {
    // 并发请求,等待所有结果
    const [userRes, postsRes, albumsRes] = await Promise.all([
      getUser(),
      getPosts(),
      getAlbums()
    ]);
    user.value = userRes.data;
    posts.value = postsRes.data;
    albums.value = albumsRes.data;
  } catch (error) {
    console.error('并发请求失败:', error);
    alert('数据加载失败');
  } finally {
    loading.value = false;
  }
};

4.2 并发请求的注意事项

  1. “全成功或全失败” 特性axios.all 和 Promise.all 均遵循 “全成功则成功,一个失败则全部失败” 的规则。若需要 “部分成功也可继续”,可使用 Promise.allSettled,它会返回所有请求的结果(成功 / 失败),需手动筛选;
  2. 性能优势:并发请求的总耗时取决于最慢的请求,而非所有请求耗时之和。例如,三个请求分别耗时 1s、2s、3s,并发时总耗时仅 3s,而串行请求则需 6s;
  3. 并发控制:若同时发起大量请求(如 10 个),可能会对服务器造成压力,此时需要实现请求队列和并发控制(如限制同时发起 3 个请求),可通过自定义队列逻辑或使用 p-limit 等第三方库实现。

五、总结与实践建议

Axios 作为 Vue3 项目中的核心网络请求工具,其使用场景覆盖了从基础请求到高阶优化的全流程。结合本文内容,我们可以总结出以下实践建议:

  1. 优先封装实例:无论项目大小,都建议封装 Axios 实例,统一配置基础 URL、超时时间和拦截器,减少冗余代码;
  2. 合理使用拦截器:请求拦截器统一处理 Token 和加载状态,响应拦截器简化数据结构和错误提示,避免在组件中重复编写相同逻辑;
  3. 重视错误处理:全面覆盖网络错误、超时、服务器错误等场景,结合 UI 组件给出友好提示,提升用户体验;
  4. 巧用并发请求:页面初始化需多接口数据时,使用 Promise.all 实现并发请求,减少加载时间;
  5. 关注类型安全:在 TypeScript 项目中,通过泛型指定 Axios 响应数据类型,避免类型错误,提升代码健壮性。

通过本文的学习,相信你已经掌握了 Axios 在 Vue3 项目中的核心用法。接下来,不妨尝试一个实战案例:搭建一个 “电影搜索” 页面,使用封装的 Axios 实例调用 OMDB API,实现搜索功能、加载状态和并发请求(搜索结果 + 电影详情),进一步巩固所学知识。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐