Axios 在 Vue 3 中的使用指南
本文档将详细介绍 Axios 在 Vue 3 中的应用,包括安装配置、基本用法、结合 Vue Router 和 Pinia 的异步数据管理、封装优化以及安全性与性能优化等内容。每个知识点都配有详细的代码示例,并提供综合性案例以帮助理解。
目录
- [Axios 概述](#Axios 概述)
- [Axios 的安装与配置](#Axios 的安装与配置)
- 发起请求与处理响应
- [在 Vue 组件中使用 Axios](#在 Vue 组件中使用 Axios)
- [Vue 3 中的 Axios 实例](#Vue 3 中的 Axios 实例)
- [Axios 结合 Vue Router 的异步加载数据](#Axios 结合 Vue Router 的异步加载数据)
- [Pinia 中的异步数据管理与 Axios](#Pinia 中的异步数据管理与 Axios)
- [Axios 公共逻辑与封装](#Axios 公共逻辑与封装)
- [创建可复用的 Axios 封装](#创建可复用的 Axios 封装)
- [处理请求的 Loading 状态](#处理请求的 Loading 状态)
- 统一处理错误提示与日志记录
- [优化 Axios 封装与配置](#优化 Axios 封装与配置)
- 安全性与性能优化
- 综合性案例
- 本章小结
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 进行网络请求和数据管理。