Vue3 学习教程,从入门到精通,Axios 在 Vue 3 中的使用指南(37)

Axios 在 Vue 3 中的使用指南

本文档将详细介绍 Axios 在 Vue 3 中的应用,包括安装配置、基本用法、结合 Vue Router 和 Pinia 的异步数据管理、封装优化以及安全性与性能优化等内容。每个知识点都配有详细的代码示例,并提供综合性案例以帮助理解。

目录

  1. [Axios 概述](#Axios 概述)
  2. [Axios 的安装与配置](#Axios 的安装与配置)
  3. 发起请求与处理响应
  4. [在 Vue 组件中使用 Axios](#在 Vue 组件中使用 Axios)
  5. [Vue 3 中的 Axios 实例](#Vue 3 中的 Axios 实例)
  6. [Axios 结合 Vue Router 的异步加载数据](#Axios 结合 Vue Router 的异步加载数据)
  7. [Pinia 中的异步数据管理与 Axios](#Pinia 中的异步数据管理与 Axios)
  8. [Axios 公共逻辑与封装](#Axios 公共逻辑与封装)
    • [创建可复用的 Axios 封装](#创建可复用的 Axios 封装)
    • [处理请求的 Loading 状态](#处理请求的 Loading 状态)
    • 统一处理错误提示与日志记录
    • [优化 Axios 封装与配置](#优化 Axios 封装与配置)
  9. 安全性与性能优化
  10. 综合性案例
  11. 本章小结

1. Axios 概述

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js。它具有以下优势:

  • 支持 Promise API
  • 支持拦截请求和响应
  • 自动转换 JSON 数据
  • 支持取消请求
  • 支持客户端和服务器端请求
  • 浏览器兼容性良好

2. Axios 的安装与配置

安装 Axios

使用 npm 或 yarn 安装 Axios:

bash 复制代码
npm install axios
# 或者
yarn add axios

配置 Axios

在 Vue 3 项目中,通常在 src 目录下创建一个 axios 文件夹,用于存放 Axios 的配置和封装。

javascript 复制代码
// src/axios/index.js
import axios from 'axios';
import { useToast } from 'vue-toastification';

// 创建 Axios 实例
const instance = axios.create({
  baseURL: 'https://api.example.com', // 基础 URL
  timeout: 10000, // 请求超时时间
});

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 在发送请求之前做些什么,例如添加认证 token
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
instance.interceptors.response.use(
  (response) => {
    // 对响应数据做点什么
    return response.data;
  },
  (error) => {
    // 对响应错误做点什么
    const toast = useToast();
    toast.error('请求失败,请稍后重试');
    return Promise.reject(error);
  }
);

export default instance;

3. 发起请求与处理响应

GET 请求

javascript 复制代码
// src/axios/get.js
import axios from './index';

export const getUser = (userId) => {
  return axios.get(`/users/${userId}`);
};

POST 请求

javascript 复制代码
// src/axios/post.js
import axios from './index';

export const createUser = (userData) => {
  return axios.post('/users', userData);
};

处理响应

javascript 复制代码
// src/components/User.vue
<template>
  <div>
    <h1>用户信息</h1>
    <p v-if="loading">加载中...</p>
    <p v-else-if="error">发生错误: {{ error }}</p>
    <div v-else>
      <p>姓名: {{ user.name }}</p>
      <p>邮箱: {{ user.email }}</p>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue';
import { getUser } from '../axios/get';

export default {
  name: 'User',
  setup() {
    const user = ref(null);
    const loading = ref(false);
    const error = ref(null);

    const fetchUser = async (id) => {
      loading.value = true;
      error.value = null;
      try {
        const response = await getUser(id);
        user.value = response;
      } catch (err) {
        error.value = err.message;
      } finally {
        loading.value = false;
      }
    };

    fetchUser(1);

    return {
      user,
      loading,
      error,
    };
  },
};
</script>

4. 在 Vue 组件中使用 Axios

在 Vue 组件中,可以通过 setup 函数或 methods 使用 Axios。

使用 setup 函数

javascript 复制代码
// src/components/PostList.vue
<template>
  <div>
    <h1>帖子列表</h1>
    <ul>
      <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';
import { getPosts } from '../axios/get';

export default {
  name: 'PostList',
  setup() {
    const posts = ref([]);

    const fetchPosts = async () => {
      const response = await getPosts();
      posts.value = response;
    };

    onMounted(() => {
      fetchPosts();
    });

    return {
      posts,
    };
  },
};
</script>

使用 methods

javascript 复制代码
// src/components/Login.vue
<template>
  <div>
    <h1>登录</h1>
    <form @submit.prevent="login">
      <input v-model="username" placeholder="用户名" />
      <input v-model="password" type="password" placeholder="密码" />
      <button type="submit">登录</button>
    </form>
    <p v-if="error">{{ error }}</p>
  </div>
</template>

<script>
import { ref } from 'vue';
import { loginUser } from '../axios/post';

export default {
  name: 'Login',
  setup() {
    const username = ref('');
    const password = ref('');
    const error = ref(null);

    const login = async () => {
      try {
        const response = await loginUser({ username: username.value, password: password.value });
        // 处理登录成功逻辑,例如保存 token
        console.log('登录成功', response);
      } catch (err) {
        error.value = '登录失败,请检查用户名和密码';
      }
    };

    return {
      username,
      password,
      login,
      error,
    };
  },
};
</script>

5. Vue 3 中的 Axios 实例

在 Vue 3 中,可以通过 app.config.globalProperties 将 Axios 实例挂载到全局属性中,方便在组件中直接使用。

javascript 复制代码
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import axios from './axios/index';

const app = createApp(App);

// 将 Axios 实例挂载到全局属性
app.config.globalProperties.$axios = axios;

app.mount('#app');

在组件中使用:

javascript 复制代码
// src/components/Example.vue
<template>
  <div>
    <h1>全局 Axios 实例示例</h1>
    <button @click="makeRequest">发起请求</button>
    <p v-if="loading">加载中...</p>
    <p v-else-if="error">错误: {{ error }}</p>
    <p v-else>响应数据: {{ data }}</p>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
  name: 'Example',
  setup() {
    const data = ref(null);
    const loading = ref(false);
    const error = ref(null);

    const makeRequest = async () => {
      loading.value = true;
      error.value = null;
      try {
        const response = await this.$axios.get('/example-endpoint');
        data.value = response;
      } catch (err) {
        error.value = err.message;
      } finally {
        loading.value = false;
      }
    };

    onMounted(() => {
      makeRequest();
    });

    return {
      data,
      loading,
      error,
      makeRequest,
    };
  },
};
</script>

6. Axios 结合 Vue Router 的异步加载数据

在 Vue Router 中,可以使用 async 函数来异步加载数据。

javascript 复制代码
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import axios from '../axios/index';
import Home from '../components/Home.vue';
import User from '../components/User.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    async beforeEnter() {
      const response = await axios.get('/home-data');
      // 可以在这里进行数据预处理
      return true;
    },
  },
  {
    path: '/user/:id',
    name: 'User',
    component: User,
    async beforeEnter(to) {
      const userId = to.params.id;
      const response = await axios.get(`/users/${userId}`);
      // 可以在这里进行数据预处理
      return true;
    },
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

7. Pinia 中的异步数据管理与 Axios

在 Pinia 中,可以使用 actions 来管理异步数据。

javascript 复制代码
// src/stores/userStore.js
import { defineStore } from 'pinia';
import axios from '../axios/index';

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [],
    loading: false,
    error: null,
  }),
  actions: {
    async fetchUsers() {
      this.loading = true;
      this.error = null;
      try {
        const response = await axios.get('/users');
        this.users = response;
      } catch (err) {
        this.error = err.message;
      } finally {
        this.loading = false;
      }
    },
  },
});

在组件中使用:

javascript 复制代码
// src/components/UserList.vue
<template>
  <div>
    <h1>用户列表</h1>
    <p v-if="userStore.loading">加载中...</p>
    <p v-else-if="userStore.error">错误: {{ userStore.error }}</p>
    <ul>
      <li v-for="user in userStore.users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

<script>
import { useUserStore } from '../stores/userStore';

export default {
  name: 'UserList',
  setup() {
    const userStore = useUserStore();

    onMounted(() => {
      userStore.fetchUsers();
    });

    return {
      userStore,
    };
  },
};
</script>

8. Axios 公共逻辑与封装

8.1 创建可复用的 Axios 封装

javascript 复制代码
// src/axios/instance.js
import axios from 'axios';
import { useToast } from 'vue-toastification';

const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});

const toast = useToast();

instance.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers['Authorization'] = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

instance.interceptors.response.use(
  (response) => {
    return response.data;
  },
  (error) => {
    toast.error('请求失败,请稍后重试');
    return Promise.reject(error);
  }
);

export default instance;

8.2 处理请求的 Loading 状态

javascript 复制代码
// src/axios/loading.js
import axios from './instance';
import { ref } from 'vue';

export const useAxiosWithLoading = () => {
  const loading = ref(false);

  const request = async (config) => {
    loading.value = true;
    try {
      const response = await axios(config);
      return response;
    } finally {
      loading.value = false;
    }
  };

  return {
    loading,
    request,
  };
};

8.3 统一处理错误提示与日志记录

javascript 复制代码
// src/axios/errorHandler.js
import { useToast } from 'vue-toastification';
import axios from './instance';

const toast = useToast();

axios.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    // 记录错误日志
    console.error('Axios 错误:', error);
    // 显示错误提示
    toast.error('请求失败,请稍后重试');
    return Promise.reject(error);
  }
);

8.4 优化 Axios 封装与配置

javascript 复制代码
// src/axios/index.js
import axios from './instance';
import { useAxiosWithLoading } from './loading';
import './errorHandler';

const { loading, request } = useAxiosWithLoading();

export { axios, loading, request };

9. 安全性与性能优化

9.1 有关网络请求的安全性

  • 认证与授权:使用 JWT 或 OAuth 进行认证,并在请求头中携带 token。
  • 数据加密:使用 HTTPS 协议,确保数据在传输过程中被加密。
  • 防止 CSRF:使用 CSRF tokens 或双重 cookie 验证。
  • 输入验证:对用户输入进行严格验证,防止 SQL 注入和 XSS 攻击。

9.2 性能优化

  • 请求缓存:使用浏览器缓存或 Axios 缓存插件,减少不必要的请求。
  • 请求合并:将多个请求合并为一个批量请求,减少网络开销。
  • 压缩数据:使用 gzip 等压缩技术,减少传输数据量。
  • 懒加载:按需加载数据,避免一次性加载过多数据。

10. 综合性案例

综合案例:用户登录与用户列表展示

javascript 复制代码
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import axios from './axios/index';
import { createPinia } from 'pinia';

const app = createApp(App);
const pinia = createPinia();

app.use(pinia);
app.use(router);
app.config.globalProperties.$axios = axios;
app.mount('#app');
javascript 复制代码
// src/stores/userStore.js
import { defineStore } from 'pinia';
import { useAxiosWithLoading } from '../axios/loading';

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [],
    currentUser: null,
    loading: false,
    error: null,
  }),
  actions: {
    async login(username, password) {
      this.loading = true;
      this.error = null;
      try {
        const response = await axios.post('/login', { username, password });
        this.currentUser = response;
        localStorage.setItem('token', response.token);
      } catch (err) {
        this.error = '登录失败,请检查用户名和密码';
      } finally {
        this.loading = false;
      }
    },
    async fetchUsers() {
      this.loading = true;
      this.error = null;
      try {
        const response = await axios.get('/users');
        this.users = response;
      } catch (err) {
        this.error = '获取用户列表失败';
      } finally {
        this.loading = false;
      }
    },
  },
});
javascript 复制代码
// src/components/Login.vue
<template>
  <div>
    <h1>登录</h1>
    <form @submit.prevent="login">
      <input v-model="username" placeholder="用户名" />
      <input v-model="password" type="password" placeholder="密码" />
      <button type="submit">登录</button>
    </form>
    <p v-if="error">{{ error }}</p>
    <p v-if="loading">加载中...</p>
  </div>
</template>

<script>
import { ref } from 'vue';
import { useUserStore } from '../stores/userStore';

export default {
  name: 'Login',
  setup() {
    const username = ref('');
    const password = ref('');
    const userStore = useUserStore();

    const login = async () => {
      await userStore.login(username.value, password.value);
    };

    return {
      username,
      password,
      login,
      error: userStore.error,
      loading: userStore.loading,
    };
  },
};
javascript 复制代码
// src/components/UserList.vue
<template>
  <div>
    <h1>用户列表</h1>
    <p v-if="userStore.loading">加载中...</p>
    <p v-else-if="userStore.error">{{ userStore.error }}</p>
    <ul>
      <li v-for="user in userStore.users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

<script>
import { useUserStore } from '../stores/userStore';

export default {
  name: 'UserList',
  setup() {
    const userStore = useUserStore();

    onMounted(() => {
      userStore.fetchUsers();
    });

    return {
      userStore,
    };
  },
};

11. 本章小结

本文档详细介绍了 Axios 在 Vue 3 中的应用,包括安装配置、基本用法、结合 Vue Router 和 Pinia 的异步数据管理、封装优化以及安全性与性能优化等内容。通过这些知识,开发者可以更高效地在 Vue 3 项目中使用 Axios 进行网络请求和数据管理。

相关推荐
冷崖2 小时前
MySQL异步连接池的学习(五)
学习·mysql
伍哥的传说3 小时前
Mitt 事件发射器完全指南:200字节的轻量级解决方案
vue.js·react.js·vue3·mitt·组件通信·事件管理·事件发射器
程序员码歌5 小时前
【零代码AI编程实战】AI灯塔导航-总结篇
android·前端·后端
用户21411832636025 小时前
免费玩转 AI 编程!Claude Code Router + Qwen3-Code 实战教程
前端
一枚小小程序员哈5 小时前
基于Vue + Node能源采购系统的设计与实现/基于express的能源管理系统#node.js
vue.js·node.js·express
焄塰7 小时前
Ansible 管理变量和事实
学习·centos·ansible
小小愿望7 小时前
前端无法获取响应头(如 Content-Disposition)的原因与解决方案
前端·后端
小小愿望7 小时前
项目启功需要添加SKIP_PREFLIGHT_CHECK=true该怎么办?
前端
任磊abc7 小时前
vscode无法检测到typescript环境解决办法
ide·vscode·typescript