在 Vue.js 中,Axios 是最常用的 HTTP 客户端库,用于发送 Ajax 请求。它基于 Promise,支持浏览器和 Node.js,具有拦截器、自动转换 JSON、取消请求等强大功能。


一、安装

npm install axios
# 或
yarn add axios

二、基础用法

1. 在组件中直接发送请求

<template>
  <div>
    <button @click="fetchData">加载数据</button>
    <ul v-if="list">
      <li v-for="item in list" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

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

const list = ref(null);
const loading = ref(false);

const fetchData = async () => {
  loading.value = true;
  try {
    const response = await axios.get('https://api.example.com/users');
    list.value = response.data;
  } catch (error) {
    console.error('请求失败:', error);
  } finally {
    loading.value = false;
  }
};
</script>

2. 常用请求方法

// GET
axios.get('/user?id=123')
  .then(response => console.log(response.data));

// GET (带 params)
axios.get('/user', { params: { id: 123 } })
  .then(response => console.log(response.data));

// POST
axios.post('/user', { name: 'Tom', age: 20 })
  .then(response => console.log(response.data));

// PUT / PATCH
axios.put('/user/123', { name: 'Jerry' });
axios.patch('/user/123', { age: 21 });

// DELETE
axios.delete('/user/123');

// 并发请求
axios.all([
  axios.get('/users'),
  axios.get('/posts')
]).then(axios.spread((usersRes, postsRes) => {
  console.log(usersRes.data, postsRes.data);
}));

三、创建 Axios 实例(推荐)

在实际项目中,不要直接在组件中 import axios,而是创建一个自定义实例,配置基础 URL、超时、拦截器等。

1. 创建实例

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

const request = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL || 'https://api.example.com',
  timeout: 5000, // 超时时间
  headers: {
    'Content-Type': 'application/json',
  },
});

export default request;

2. 在组件中使用

<script setup>
import request from '@/utils/request';

const getUser = async () => {
  const res = await request.get('/user/123');
  console.log(res.data);
};
</script>

四、请求与响应拦截器

拦截器是 Axios 最强大的功能,用于统一处理请求头错误Token等。

1. 添加拦截器

// src/utils/request.js
import axios from 'axios';
import { ElMessage } from 'element-plus'; // 假设使用 Element Plus

const request = axios.create({
  baseURL: '/api',
  timeout: 5000,
});

// 请求拦截器:发送前处理
request.interceptors.request.use(
  (config) => {
    // 1. 添加 Token
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }

    // 2. 处理 GET 请求的 params
    if (config.method === 'get') {
      config.params = { ...config.params, timestamp: Date.now() };
    }

    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器:收到响应后处理
request.interceptors.response.use(
  (response) => {
    // 假设后端统一返回 { code: 200, data: ..., msg: 'success' }
    const { code, data, msg } = response.data;

    if (code === 200) {
      return data; // 直接返回 data,组件中无需再解构
    } else {
      ElMessage.error(msg || '请求失败');
      return Promise.reject(new Error(msg));
    }
  },
  (error) => {
    // 处理 HTTP 状态码错误
    if (error.response) {
      const { status } = error.response;
      switch (status) {
        case 401:
          ElMessage.error('未登录,请重新登录');
          localStorage.removeItem('token');
          // 跳转登录页
          // router.push('/login');
          break;
        case 403:
          ElMessage.error('无权限访问');
          break;
        case 404:
          ElMessage.error('资源不存在');
          break;
        case 500:
          ElMessage.error('服务器错误');
          break;
        default:
          ElMessage.error('网络错误');
      }
    } else if (error.request) {
      // 请求已发送但未收到响应
      ElMessage.error('网络超时,请检查连接');
    } else {
      // 请求配置出错
      ElMessage.error('请求配置错误');
    }
    return Promise.reject(error);
  }
);

export default request;

2. 组件中使用(简化)

<script setup>
import request from '@/utils/request';

const fetchData = async () => {
  try {
    // 拦截器已经处理了 token 和错误,这里直接拿到 data
    const data = await request.get('/users');
    console.log(data);
  } catch (error) {
    // 错误已在拦截器中处理,这里可选做额外逻辑
  }
};
</script>

五、取消请求

在组件卸载或用户快速切换时,取消未完成的请求,避免内存泄漏和状态错乱。

1. 使用 AbortController(推荐)

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

const data = ref(null);
const controller = new AbortController();

const fetchData = async () => {
  try {
    const res = await axios.get('/users', {
      signal: controller.signal, // 绑定信号
    });
    data.value = res.data;
  } catch (error) {
    if (axios.isCancel(error)) {
      console.log('请求已取消:', error.message);
    } else {
      console.error('请求失败:', error);
    }
  }
};

// 组件卸载时取消请求
onUnmounted(() => {
  controller.abort();
});
</script>

2. 使用 CancelToken(旧版,Vue 2 常用)

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/users', {
  cancelToken: source.token
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  }
});

// 取消
source.cancel('Operation canceled by the user.');

六、封装 API 模块(最佳实践)

将 API 请求按模块拆分,统一管理。

// src/api/user.js
import request from '@/utils/request';

export function login(data) {
  return request({
    url: '/auth/login',
    method: 'post',
    data,
  });
}

export function getUserInfo() {
  return request({
    url: '/user/info',
    method: 'get',
  });
}

export function updateUser(data) {
  return request({
    url: '/user/update',
    method: 'put',
    data,
  });
}
<!-- 组件中使用 -->
<script setup>
import { login, getUserInfo } from '@/api/user';

const handleLogin = async () => {
  const res = await login({ username: 'tom', password: '123' });
  console.log(res);
};
</script>

七、Vue 2 vs Vue 3 差异

特性 Vue 2 Vue 3
导入方式 import axios from 'axios' 同上
生命周期 mounted() onMounted()
取消请求 CancelToken AbortController (推荐)
响应拦截器 同上 同上

八、总结

场景 推荐方案
简单请求 直接 axios.get/post
项目级请求 创建 axios.create() 实例
统一处理 Token/错误 请求/响应拦截器
取消请求 AbortController (Vue 3)
代码组织 按模块封装 API 文件

核心流程

  1. 安装 Axios。
  2. 创建自定义实例(配置 baseURL、timeout)。
  3. 添加拦截器(统一处理 Token、错误)。
  4. 封装 API 模块(按业务拆分)。
  5. 在组件中调用 API。

Axios 是 Vue 项目处理网络请求的事实标准,配合拦截器和模块化封装,可以极大提升开发效率和代码可维护性。

更多推荐