Vue基础教程(183)使用axios创建请求:别再用fetch了!Vue中axios让你优雅搞定网络请求,香到炸裂!

嘿,老铁!是不是还在Vue项目里跟网络请求较劲?每次看到fetch那冗长的代码就想砸键盘?别急,今天我要给你安利一个神器——axios,这玩意儿能让你的网络请求变得像喝奶茶一样丝滑!

为什么是axios,而不是fetch?

先说说为啥要选axios。fetch不是不能用,但它就像个毛坯房,啥都得自己装修。比如,fetch默认不会处理错误,得手动检查response.ok;返回的数据得自己转JSON;还没有请求超时和取消功能……想想就头大!

axios就不一样了,它是个精装房,拎包入住!自动转换JSON数据、智能处理错误、请求响应拦截、CSRF防护、甚至还能取消请求——这些功能开箱即用,爽不爽?

举个栗子,用fetch发个POST请求得这么写:

fetch('/api/user', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: '小明',
    age: 18
  })
})
.then(response => {
  if (!response.ok) {
    throw new Error('网络响应不正常');
  }
  return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('出错啦:', error));

而用axios,简洁到飞起:

axios.post('/api/user', {
  name: '小明', 
  age: 18
})
.then(response => console.log(response.data))
.catch(error => console.error('出错啦:', error));

看到没?代码少了一半,可读性还更强!这就是为什么Vue社区几乎清一色选择axios的原因。

手把手教你安装配置axios

好了,口水话不多说,咱们直接上手!在你的Vue项目里安装axios:

npm install axios
# 或者
yarn add axios

安装完怎么用?有三种姿势,从菜鸟到高手任君选择:

姿势一:简单粗暴式 - 适合小项目

直接在组件里引入就用:

import axios from 'axios';

export default {
  methods: {
    async fetchUser() {
      try {
        const response = await axios.get('/api/user/123');
        this.user = response.data;
      } catch (error) {
        console.error('获取用户失败:', error);
      }
    }
  }
}

姿势二:全局注册式 - 推荐大多数项目

在main.js里配置,整个项目都能用:

import { createApp } from 'vue';
import axios from 'axios';
import App from './App.vue';

const app = createApp(App);

// 全局配置axios
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;

// 挂载到Vue原型上,组件内直接用this.$axios
app.config.globalProperties.$axios = axios;

app.mount('#app');

然后在组件里就能愉快地使用了:

export default {
  methods: {
    async getUser() {
      try {
        const response = await this.$axios.get('/user/123');
        return response.data;
      } catch (error) {
        this.$message.error('获取数据失败');
      }
    }
  }
}

姿势三:封装服务式 - 企业级大项目必备

创建src/api/request.js文件进行高级封装:

import axios from 'axios';
import { Message } from 'element-ui'; // 如果你用了UI框架

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 10000,
});

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

// 响应拦截器 - 收到响应后做什么
service.interceptors.response.use(
  response => {
    const res = response.data;
    
    // 根据后端返回码判断请求状态
    if (res.code !== 200) {
      Message.error(res.message || '请求失败');
      return Promise.reject(new Error(res.message || 'Error'));
    } else {
      return res;
    }
  },
  error => {
    // 处理HTTP网络错误
    let message = '网络异常,请稍后重试';
    if (error.response) {
      switch (error.response.status) {
        case 401:
          message = '未授权,请重新登录';
          // 跳转到登录页
          break;
        case 403:
          message = '拒绝访问';
          break;
        case 404:
          message = '请求地址不存在';
          break;
        case 500:
          message = '服务器内部错误';
          break;
        default:
          message = `连接错误${error.response.status}`;
      }
    }
    Message.error(message);
    return Promise.reject(error);
  }
);

export default service;

然后在具体的API模块中使用:

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

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

export function updateUser(userData) {
  return request({
    url: '/user/update',
    method: 'post',
    data: userData
  });
}

实战!完整用户管理系统示例

光说不练假把式,来看个完整的用户管理组件:

<template>
  <div class="user-management">
    <h2>用户管理系统</h2>
    
    <!-- 查询区域 -->
    <div class="search-box">
      <el-input v-model="searchKeyword" placeholder="输入用户名搜索" style="width: 300px" />
      <el-button type="primary" @click="handleSearch">搜索</el-button>
      <el-button @click="handleAdd">新增用户</el-button>
    </div>
    
    <!-- 用户列表 -->
    <el-table :data="userList" v-loading="loading">
      <el-table-column prop="id" label="ID" width="80" />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="email" label="邮箱" />
      <el-table-column prop="createTime" label="创建时间" />
      <el-table-column label="操作">
        <template #default="scope">
          <el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
          <el-button size="small" type="danger" @click="handleDelete(scope.row.id)">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <!-- 分页 -->
    <el-pagination
      :current-page="pagination.current"
      :page-size="pagination.size"
      :total="pagination.total"
      @current-change="handlePageChange"
      layout="total, prev, pager, next, jumper"
    />
    
    <!-- 新增/编辑对话框 -->
    <el-dialog :title="dialogTitle" v-model="dialogVisible">
      <el-form :model="userForm" :rules="formRules" ref="userFormRef" label-width="80px">
        <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>
import { getUserList, createUser, updateUser, deleteUser } from '@/api/user';

export default {
  name: 'UserManagement',
  data() {
    return {
      searchKeyword: '',
      loading: false,
      userList: [],
      pagination: {
        current: 1,
        size: 10,
        total: 0
      },
      dialogVisible: false,
      dialogType: 'add', // 'add' or 'edit'
      userForm: {
        id: null,
        name: '',
        email: ''
      },
      formRules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        email: [
          { required: true, message: '请输入邮箱', trigger: 'blur' },
          { type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
        ]
      }
    };
  },
  computed: {
    dialogTitle() {
      return this.dialogType === 'add' ? '新增用户' : '编辑用户';
    }
  },
  mounted() {
    this.loadUserList();
  },
  methods: {
    // 加载用户列表
    async loadUserList() {
      this.loading = true;
      try {
        const params = {
          page: this.pagination.current,
          size: this.pagination.size,
          keyword: this.searchKeyword
        };
        
        const result = await getUserList(params);
        this.userList = result.data.list;
        this.pagination.total = result.data.total;
      } catch (error) {
        console.error('加载用户列表失败:', error);
      } finally {
        this.loading = false;
      }
    },
    
    // 搜索用户
    handleSearch() {
      this.pagination.current = 1;
      this.loadUserList();
    },
    
    // 新增用户
    handleAdd() {
      this.dialogType = 'add';
      this.userForm = { id: null, name: '', email: '' };
      this.dialogVisible = true;
    },
    
    // 编辑用户
    handleEdit(user) {
      this.dialogType = 'edit';
      this.userForm = { ...user };
      this.dialogVisible = true;
    },
    
    // 提交表单
    async handleSubmit() {
      try {
        await this.$refs.userFormRef.validate();
        
        if (this.dialogType === 'add') {
          await createUser(this.userForm);
          this.$message.success('新增用户成功');
        } else {
          await updateUser(this.userForm);
          this.$message.success('更新用户成功');
        }
        
        this.dialogVisible = false;
        this.loadUserList(); // 重新加载列表
      } catch (error) {
        if (error.fields) {
          this.$message.warning('请完善表单信息');
        } else {
          console.error('提交失败:', error);
        }
      }
    },
    
    // 删除用户
    async handleDelete(userId) {
      try {
        await this.$confirm('确定删除该用户吗?', '提示', {
          type: 'warning'
        });
        
        await deleteUser(userId);
        this.$message.success('删除用户成功');
        this.loadUserList();
      } catch (error) {
        if (error === 'cancel') {
          this.$message.info('已取消删除');
        } else {
          console.error('删除失败:', error);
        }
      }
    },
    
    // 分页变化
    handlePageChange(currentPage) {
      this.pagination.current = currentPage;
      this.loadUserList();
    }
  }
};
</script>
<style scoped>
.user-management {
  padding: 20px;
}
.search-box {
  margin-bottom: 20px;
}
</style>

高级技巧:让你的请求更优雅

1. 请求取消 - 告别无用请求

在搜索场景中,用户连续输入时,前一个请求可能还没返回,后一个请求就发出了。这时候需要取消前一个请求:

// 在API文件中
let cancelRequest = null;

export function searchUsers(keyword) {
  // 如果已有请求在进行,先取消
  if (cancelRequest) {
    cancelRequest('取消重复请求');
  }
  
  return request({
    url: '/user/search',
    method: 'get',
    params: { keyword },
    cancelToken: new axios.CancelToken(function executor(c) {
      cancelRequest = c;
    })
  });
}

2. 自动重试 - 增强用户体验

对于某些临时性错误,可以设置自动重试:

// 重试函数
function retryRequest(axiosInstance, retryCount = 3) {
  return async function(config) {
    let lastError;
    for (let i = 0; i < retryCount; i++) {
      try {
        return await axiosInstance(config);
      } catch (error) {
        lastError = error;
        // 如果是网络错误或5xx错误,进行重试
        if (!error.response || error.response.status >= 500) {
          console.warn(`请求失败,第${i + 1}次重试...`);
          // 等待一段时间再重试
          await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
          continue;
        }
        break;
      }
    }
    throw lastError;
  };
}

// 使用示例
const apiWithRetry = retryRequest(axios);
const result = await apiWithRetry({ url: '/api/data' });

3. 请求缓存 - 提升性能

对于一些不常变化的数据,可以添加缓存:

const cache = new Map();

export function getCachedData(url, forceRefresh = false) {
  // 强制刷新或缓存不存在时重新请求
  if (forceRefresh || !cache.has(url)) {
    const promise = axios.get(url).catch(error => {
      // 请求失败时清除缓存
      cache.delete(url);
      throw error;
    });
    cache.set(url, promise);
  }
  return cache.get(url);
}

常见坑位及填坑指南

坑1:this指向问题
在axios回调函数中,this可能不是Vue实例。解决方案:使用箭头函数或bind。

// 错误写法
axios.get('/api/data').then(function(response) {
  this.data = response.data; // this不是Vue实例!
});

// 正确写法 - 箭头函数
axios.get('/api/data').then(response => {
  this.data = response.data;
});

// 正确写法 - bind
axios.get('/api/data').then(function(response) {
  this.data = response.data;
}.bind(this));

坑2:Vue 3的响应式更新
在Vue 3中,直接给响应式对象赋值可能不会触发更新:

// 可能不会触发更新
const state = reactive({ user: {} });
axios.get('/api/user').then(response => {
  state.user = response.data; // 直接替换可能有问题
});

// 更好的做法 - 逐个属性赋值
axios.get('/api/user').then(response => {
  Object.assign(state.user, response.data);
});

// 或者使用ref
const user = ref({});
axios.get('/api/user').then(response => {
  user.value = response.data; // 这样是可以的
});

结语

axios在Vue项目中的地位,就像奶茶里的珍珠——没有它也能喝,但有了它才完整!从简单的GET请求到复杂的企业级应用,axios都能优雅应对。

记住,好的网络请求处理不仅能让代码更整洁,还能显著提升用户体验。现在就去你的Vue项目里试试axios吧,保证让你直呼"真香"!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

值引力

持续创作,多谢支持!

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

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

打赏作者

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

抵扣说明:

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

余额充值