Vue基础教程(184)axios请求配置:别再用老掉牙的请求方式了!Axios这样玩才够溜

一、为什么说Axios是Vue开发的“灵魂伴侣”?

各位前端er,不知道你们有没有这样的经历:用原生fetch写请求时,感觉自己像个“网络乞丐”,每个请求都要重复写一堆配置,错误处理更是让人头大。直到遇见了Axios——这货简直就是前端界的“瑞士军刀”!

先来说说Axios凭什么能成为Vue官方推荐的请求库:

1. 开箱即用的爽感

// 不用Axios时(痛苦面具)
fetch('/api/user', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + token
  }
})
.then(response => {
  if (!response.ok) throw new Error('Network error');
  return response.json();
})

// 用了Axios后(真香!)
axios.get('/api/user', {
  headers: { 'Authorization': 'Bearer ' + token }
})

2. 浏览器兼容性拉满
IE11?抱歉,fetch真的不熟。Axios却能让你的应用在各类浏览器里畅通无阻,这就是底气!

3. 进度监控超能力
上传下载进度条?Axios轻松搞定,用户体验直接拉满。

二、Axios基础配置:从“能用”到“好用”

2.1 安装与引入的“正确姿势”
npm install axios

在Vue项目中,我强烈推荐创建单独的请求模块:

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

// 创建实例 - 这是专业项目的标配
const request = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL || '/api',
  timeout: 10000, // 10秒超时,防止用户变成“等等党”
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
});

export default request;
2.2 核心配置项详解
// 这些配置项记牢,面试都能多拿2k!
const config = {
  // 请求的服务器URL(必填)
  url: '/user',
  
  // 请求方法,默认get(选填)
  method: 'get', // 可选:get, post, put, delete...
  
  // 基础URL路径(智能拼接)
  baseURL: 'https://api.example.com',
  
  // 自定义请求头(装X必备)
  headers: { 'X-Custom-Header': 'foobar' },
  
  // URL参数(GET请求专用)
  params: { id: 12345 },
  
  // 请求体数据(POST/PUT专用)
  data: { name: '张三', age: 18 },
  
  // 超时时间(单位毫秒)
  timeout: 5000,
  
  // 响应数据类型
  responseType: 'json', // 可选:arraybuffer, blob, document, json, text, stream
}

三、拦截器:Axios的“魔法道具”

拦截器就是Axios的灵魂所在,用好它能让你的代码优雅度提升200%!

3.1 请求拦截器:给每个请求“化个妆”
// 统一添加token,告别重复代码
request.interceptors.request.use(
  (config) => {
    // 在发送请求前做些羞羞的事
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    // 显示loading动画
    showLoading();
    
    return config;
  },
  (error) => {
    // 对请求错误做些什么(比如:请求配置有问题)
    hideLoading();
    return Promise.reject(error);
  }
);
3.2 响应拦截器:统一处理错误和数据
request.interceptors.response.use(
  (response) => {
    // 2xx范围内的状态码都会触发该函数
    hideLoading();
    
    // 如果后端返回的数据结构是 { code: 200, data: {}, message: 'success' }
    const { code, data, message } = response.data;
    
    if (code === 200) {
      return data; // 直接返回真正的数据,爽!
    } else {
      // 业务逻辑错误
      ElMessage.error(message || '系统异常');
      return Promise.reject(new Error(message || 'Error'));
    }
  },
  (error) => {
    // 超出2xx范围的状态码都会触发该函数
    hideLoading();
    
    // 根据HTTP状态码做不同的错误处理
    if (error.response?.status === 401) {
      ElMessage.error('登录已过期,请重新登录');
      router.push('/login');
    } else if (error.response?.status === 403) {
      ElMessage.error('没有权限访问该资源');
    } else if (error.response?.status === 500) {
      ElMessage.error('服务器开小差了,请稍后重试');
    } else if (error.code === 'ECONNABORTED') {
      ElMessage.error('请求超时,请检查网络连接');
    } else {
      ElMessage.error('网络异常,请稍后重试');
    }
    
    return Promise.reject(error);
  }
);

四、实战:用户管理系统完整示例

下面我们来搞个真实的用户管理系统,看看Axios在实战中怎么用:

4.1 API模块化封装
// src/api/user.js
import request from '@/utils/request';

// 用户相关的所有API请求
export const userAPI = {
  // 获取用户列表
  getUsers(params) {
    return request.get('/users', { params });
  },
  
  // 获取用户详情
  getUserDetail(id) {
    return request.get(`/users/${id}`);
  },
  
  // 创建用户
  createUser(data) {
    return request.post('/users', data);
  },
  
  // 更新用户
  updateUser(id, data) {
    return request.put(`/users/${id}`, data);
  },
  
  // 删除用户
  deleteUser(id) {
    return request.delete(`/users/${id}`);
  },
  
  // 批量删除用户
  batchDeleteUsers(ids) {
    return request.post('/users/batch-delete', { ids });
  }
};
4.2 在Vue组件中使用
<template>
  <div class="user-management">
    <!-- 用户列表 -->
    <el-table :data="userList" v-loading="loading">
      <el-table-column prop="name" label="姓名"></el-table-column>
      <el-table-column prop="email" label="邮箱"></el-table-column>
      <el-table-column label="操作">
        <template #default="scope">
          <el-button @click="handleEdit(scope.row)">编辑</el-button>
          <el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 添加用户表单 -->
    <el-dialog v-model="dialogVisible" title="添加用户">
      <el-form :model="userForm" :rules="rules" ref="formRef">
        <el-form-item label="姓名" prop="name">
          <el-input v-model="userForm.name" />
        </el-form-item>
        <el-form-item label="邮箱" prop="email">
          <el-input v-model="userForm.email" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="handleSubmit">确定</el-button>
      </template>
    </el-dialog>
  </div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { userAPI } from '@/api/user';

const loading = ref(false);
const dialogVisible = ref(false);
const userList = ref([]);
const formRef = ref();

const userForm = reactive({
  name: '',
  email: ''
});

const rules = {
  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
  email: [
    { required: true, message: '请输入邮箱', trigger: 'blur' },
    { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
  ]
};

// 获取用户列表
const fetchUsers = async () => {
  try {
    loading.value = true;
    const data = await userAPI.getUsers({
      page: 1,
      pageSize: 10
    });
    userList.value = data.list;
  } catch (error) {
    console.error('获取用户列表失败:', error);
  } finally {
    loading.value = false;
  }
};

// 添加用户
const handleSubmit = async () => {
  try {
    await formRef.value.validate();
    await userAPI.createUser(userForm);
    ElMessage.success('添加用户成功');
    dialogVisible.value = false;
    fetchUsers(); // 重新获取列表
  } catch (error) {
    // 错误已经在拦截器里统一处理了,这里不用再写ElMessage
  }
};

// 删除用户
const handleDelete = async (id) => {
  try {
    await ElMessageBox.confirm('确定删除该用户吗?', '提示', {
      type: 'warning'
    });
    
    await userAPI.deleteUser(id);
    ElMessage.success('删除成功');
    fetchUsers();
  } catch (error) {
    if (error === 'cancel') {
      ElMessage.info('已取消删除');
    }
  }
};

onMounted(() => {
  fetchUsers();
});
</script>

五、高级技巧:让你的Axios更“聪明”

5.1 取消重复请求:防止用户“手抖”
// 用于存储正在进行中的请求
const pendingRequests = new Map();

// 生成请求的key
const generateReqKey = (config) => {
  return [config.method, config.url, JSON.stringify(config.params), JSON.stringify(config.data)].join('&');
};

// 添加请求到pending中
const addPendingRequest = (config) => {
  const key = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
    if (!pendingRequests.has(key)) {
      pendingRequests.set(key, cancel);
    }
  });
};

// 移除请求
const removePendingRequest = (config) => {
  const key = generateReqKey(config);
  if (pendingRequests.has(key)) {
    const cancel = pendingRequests.get(key);
    cancel(key);
    pendingRequests.delete(key);
  }
};

// 在请求拦截器中添加
request.interceptors.request.use(config => {
  removePendingRequest(config); // 检查是否存在重复请求,若存在则取消
  addPendingRequest(config); // 把当前请求添加到pending中
  return config;
});

// 在响应拦截器中移除
request.interceptors.response.use(response => {
  removePendingRequest(response.config);
  return response;
}, error => {
  removePendingRequest(error.config || {});
  return Promise.reject(error);
});
5.2 自动重试机制:给请求“上保险”
// 重试配置
const retryConfig = {
  retries: 3, // 重试次数
  retryDelay: 1000, // 重试延迟
};

const retryRequest = (config) => {
  return new Promise((resolve, reject) => {
    const attempt = (retryCount) => {
      request(config)
        .then(resolve)
        .catch((error) => {
          if (retryCount > 0 && shouldRetry(error)) {
            setTimeout(() => {
              attempt(retryCount - 1);
            }, retryConfig.retryDelay);
          } else {
            reject(error);
          }
        });
    };
    attempt(retryConfig.retries);
  });
};

const shouldRetry = (error) => {
  // 只在网络错误或5xx错误时重试
  return !error.response || error.response.status >= 500;
};

六、多环境配置:一套代码走天下

// .env.development
VUE_APP_API_BASE_URL=http://localhost:3000/api
VUE_APP_MODE=development

// .env.production
VUE_APP_API_BASE_URL=https://api.yourdomain.com
VUE_APP_MODE=production

// .env.test
VUE_APP_API_BASE_URL=https://test-api.yourdomain.com
VUE_APP_MODE=test

// 在axios配置中使用
const request = axios.create({
  baseURL: process.env.VUE_APP_API_BASE_URL,
  timeout: 10000,
});

七、常见坑点与解决方案

坑点1:POST请求变成OPTIONS

// 问题:浏览器先发OPTIONS预检请求
// 解决:后端配置CORS,或者简单请求避免预检
const config = {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded' // 简单请求
  }
}

坑点2:请求超时设置不合理

// 根据不同请求类型设置不同超时时间
const getTimeout = (url) => {
  if (url.includes('/upload')) return 30000; // 上传文件给30秒
  if (url.includes('/export')) return 60000; // 导出数据给1分钟
  return 10000; // 普通请求10秒
}

八、总结

看到这里,相信你已经从Axios的“入门小白”晋级为“配置高手”了!记住几个核心要点:

  1. 实例化是基础 - 别再用axios直接调用了
  2. 拦截器是灵魂 - 统一处理让代码更优雅
  3. 错误处理要全面 - 给用户更好的体验
  4. API要模块化 - 维护起来真香

Axios的配置就像做菜,基础的调料大家都一样,但秘制酱料才是决定味道的关键。希望本文的“秘制配方”能帮你做出更美味的“前端大餐”!

最后的忠告:别再做“CV工程师”了,把这些配置封装成你自己的请求库,下次新项目直接拿来就用,老板看了直呼内行!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值