vue学习---基于vue2中的axios

vue学习---基于vue2中的axios

一、背景与问题

在Vue2项目开发中,前后端分离架构已成为主流。前端需要通过HTTP请求与后端API进行数据交互,而axios作为主流的HTTP客户端库,其高效、灵活的特性使得它成为Vue项目中最常用的网络请求解决方案。

传统fetch API存在诸多限制:无法直接拦截请求/响应、缺乏自动转换JSON数据、缺少请求/响应拦截器等。而axios通过封装XMLHttpRequest,提供了更强大的功能,包括:

  • 自动转换JSON数据
  • 支持Promise API
  • 提供拦截器机制
  • 支持请求/响应的拦截处理
  • 自动处理HTTP错误状态码

在实际开发中,常见的问题包括:

  • 跨域问题(CORS)
  • 请求超时处理
  • 错误处理不完善
  • 缺乏统一的请求封装
  • 安全性隐患

二、基本原理

1. axios底层实现

axios基于XMLHttpRequest进行封装,通过创建Axios类实现核心功能。其核心原理包括:

  • 建立请求配置对象
  • 创建XMLHttpRequest实例
  • 设置请求头、方法、超时等参数
  • 监听onload和onerror事件
  • 处理响应数据和错误
// axios核心封装(简化版)
function createAxios(config) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open(config.method, config.url, true);
    
    xhr.onload = function() {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.responseText));
      } else {
        reject({ status: xhr.status, data: xhr.responseText });
      }
    };
    
    xhr.onerror = function() {
      reject({ status: 0, data: 'Network error' });
    };
    
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.send(JSON.stringify(config.data));
  });
}

2. 请求/响应拦截器机制

axios通过axios.interceptors提供拦截器功能,分为请求拦截器和响应拦截器:

// 请求拦截器示例
axios.interceptors.request.use(config => {
  // 添加请求头
  config.headers.Authorization = 'Bearer ' + getToken();
  
  // 添加请求时间戳
  config.headers['X-Request-Time'] = Date.now();
  
  return config;
}, error => {
  // 请求错误处理
  console.error('Request error:', error);
  return Promise.reject(error);
});

// 响应拦截器示例
axios.interceptors.response.use(response => {
  // 处理响应数据
  if (response.data.code === 200) {
    return response.data.data;
  } else {
    throw new Error(response.data.message);
  }
}, error => {
  // 响应错误处理
  console.error('Response error:', error);
  return Promise.reject(error);
});

3. 并发请求处理

通过axios.all和axios.spread处理多个并发请求:

axios.all([
  axios.get('/api/users'),
  axios.get('/api/posts')
]).then(axios.spread((users, posts) => {
  console.log('Users:', users);
  console.log('Posts:', posts);
}));

三、环境准备

1. 项目依赖

在Vue2项目中需要安装axios:

npm install axios --save

2. 项目结构建议

src/
├── api/          # API接口封装
├── utils/        # 工具函数
├── services/     # 服务模块
├── main.js       # 入口文件
├── App.vue       # 根组件
└── axios.js      # axios配置文件

四、核心实现

1. 创建axios实例

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

// 创建axios实例
const service = axios.create({
  baseURL: process.env.VUE_APP_API_URL, // 从.env文件读取API地址
  timeout: 10000, // 超时时间
  withCredentials: true, // 允许跨域请求携带cookie
});

// 添加请求拦截器
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 => {
  if (response.data.code === 200) {
    return response.data.data;
  } else {
    // 统一错误处理
    const message = response.data.message || 'Server error';
    return Promise.reject(new Error(message));
  }
}, error => {
  if (error.response) {
    // 接收到响应但状态码不在2xx范围
    console.error('Server error:', error.response.status);
  } else if (error.request) {
    // 没有收到响应
    console.error('No response received');
  } else {
    // 请求初始化错误
    console.error('Request error:', error.message);
  }
  return Promise.reject(error);
});

export default service;

2. 封装请求方法

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

// 封装get请求
export function get(url, params) {
  return service.get(url, { params });
}

// 封装post请求
export function post(url, data) {
  return service.post(url, data);
}

// 封装put请求
export function put(url, data) {
  return service.put(url, data);
}

// 封装delete请求
export function del(url, params) {
  return service.delete(url, { params });
}

3. 带拦截器的请求示例

// src/components/UserList.vue
<template>
  <div>
    <ul>
      <li v-for="user in users" :key="user.id">{{ user.name }}</li>
    </ul>
  </div>
</template>

<script>
import { get } from '@/utils/request';

export default {
  data() {
    return {
      users: []
    };
  },
  mounted() {
    this.fetchUsers();
  },
  methods: {
    async fetchUsers() {
      try {
        const res = await get('/api/users');
        this.users = res;
      } catch (error) {
        console.error('Failed to fetch users:', error);
        this.users = [];
      }
    }
  }
};
</script>

五、完整案例

1. 用户管理系统案例

项目结构

src/
├── api/
│   └── user.js
├── services/
│   └── user.js
├── utils/
│   └── request.js
├── axios.js
├── main.js
├── App.vue
└── UserList.vue

API接口定义

// src/api/user.js
export const list = '/api/users';
export const detail = '/api/users/:id';
export const create = '/api/users';
export const update = '/api/users/:id';
export const remove = '/api/users/:id';

服务模块

// src/services/user.js
import { get, post, put, del } from '@/utils/request';
import { list, detail, create, update, remove } from '@/api/user';

export async function fetchUsers() {
  return get(list);
}

export async function fetchUser(id) {
  return get(detail.replace(':id', id));
}

export async function createUser(data) {
  return post(create, data);
}

export async function updateUser(id, data) {
  return put(update.replace(':id', id), data);
}

export async function deleteUser(id) {
  return del(remove.replace(':id', id));
}

组件使用示例

// src/components/UserList.vue
<template>
  <div>
    <div>用户列表</div>
    <ul>
      <li v-for="user in users" :key="user.id">
        {{ user.name }} - {{ user.email }}
        <button @click="deleteUser(user.id)">删除</button>
      </li>
    </ul>
  </div>
</template>

<script>
import { fetchUsers, deleteUser } from '@/services/user';

export default {
  data() {
    return {
      users: []
    };
  },
  mounted() {
    this.fetchUsers();
  },
  methods: {
    async fetchUsers() {
      try {
        const res = await fetchUsers();
        this.users = res;
      } catch (error) {
        console.error('Failed to fetch users:', error);
        this.users = [];
      }
    },
    async deleteUser(id) {
      try {
        await deleteUser(id);
        this.users = this.users.filter(user => user.id !== id);
        alert('删除成功');
      } catch (error) {
        console.error('Delete error:', error);
        alert('删除失败');
      }
    }
  }
};
</script>

六、源码解析

1. axios源码核心结构

axios源码主要包含以下几个核心模块:

  • createInstance:创建axios实例
  • createInterceptor:创建拦截器
  • createRequest:创建请求
  • createResponse:创建响应
  • createError:创建错误对象
// 简化版源码结构
function createInstance(config) {
  const instance = {
    defaults: {},
    interceptors: {
      request: {
        handlers: [],
        use: (fulfilled, rejected) => {
          // 添加请求拦截器
        }
      },
      response: {
        handlers: [],
        use: (fulfilled, rejected) => {
          // 添加响应拦截器
        }
      }
    },
    request: function(config) {
      // 创建请求
    }
  };
  
  return instance;
}

2. 请求拦截器执行顺序

// 请求拦截器执行流程
requestConfig
  .then(interceptors.request.handlers[0])
  .then(interceptors.request.handlers[1])
  .then(...)
  .then(config => {
    // 发起请求
  })

七、进阶使用

1. 自定义拦截器

// 自定义请求拦截器
service.interceptors.request.use(config => {
  // 添加请求头
  config.headers['X-App-Version'] = '1.0.0';
  
  // 添加请求时间戳
  config.headers['X-Request-Time'] = Date.now();
  
  // 添加请求参数
  config.params = {
    ...config.params,
    timestamp: Date.now()
  };
  
  return config;
}, error => {
  return Promise.reject(error);
});

2. 并发请求优化

// 使用axios.all处理并发请求
axios.all([
  axios.get('/api/users'),
  axios.get('/api/posts')
]).then(axios.spread((users, posts) => {
  console.log('Users:', users);
  console.log('Posts:', posts);
}));

3. 安全增强措施

// 添加安全请求头
config.headers['X-Content-Type-Options'] = 'nosniff';
config.headers['X-Frame-Options'] = 'SAMEORIGIN';
config.headers['X-XSS-Protection'] = '1; mode=block';

八、性能与工程实践

1. 性能优化策略

(1) 缓存机制

// 使用本地缓存
const cache = new Map();

function getWithCache(url, params) {
  const key = `${url}?${new URLSearchParams(params).toString()}`;
  if (cache.has(key)) {
    return Promise.resolve(cache.get(key));
  }
  return service.get(url, { params }).then(data => {
    cache.set(key, data);
    return data;
  });
}

(2) 并发控制

// 使用并发控制
const pendingRequests = new Map();

function getWithConcurrency(url, params) {
  const key = `${url}?${new URLSearchParams(params).toString()}`;
  
  if (pendingRequests.has(key)) {
    return pendingRequests.get(key);
  }
  
  const promise = service.get(url, { params }).then(data => {
    pendingRequests.delete(key);
    return data;
  }).catch(error => {
    pendingRequests.delete(key);
    throw error;
  });
  
  pendingRequests.set(key, promise);
  return promise;
}

(3) 超时控制

// 设置超时时间
const timeout = 5000; // 5秒
service.interceptors.request.use(config => {
  config.timeout = timeout;
  return config;
});

2. 异常处理规范

// 统一错误处理
service.interceptors.response.use(response => {
  if (response.data.code === 200) {
    return response.data.data;
  } else {
    const message = response.data.message || 'Server error';
    return Promise.reject(new Error(message));
  }
}, error => {
  if (error.response) {
    // 接收到响应但状态码不在2xx范围
    console.error(`Server error: ${error.response.status}`);
  } else if (error.request) {
    // 没有收到响应
    console.error('No response received');
  } else {
    // 请求初始化错误
    console.error('Request error:', error.message);
  }
  return Promise.reject(error);
});

3. 安全性实践

(1) 跨域解决方案

// 后端CORS配置示例(Node.js)
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  next();
});

(2) 请求签名机制

// 请求签名生成
function generateSign(params, secret) {
  const sortedParams = Object.keys(params).sort().map(key => 
    `${key}=${params[key]}`).join('&');
  return CryptoJS.HmacSHA256(sortedParams, secret).toString();
}

九、常见问题与踩坑

1. 跨域问题(CORS)

错误现象:浏览器控制台显示No 'Access-Control-Allow-Origin' header is present on the requested resource

解决方法:

  • 后端配置CORS
  • 使用代理服务器(开发环境)
  • 使用axios的withCredentials配置
// 开发环境代理配置(vue.config.js)
module.exports = {
  devServer: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
      }
    }
  }
};

2. 错误处理不完善

错误现象:网络异常时页面崩溃

改进方法:添加全局错误处理

// 全局错误处理
window.onerror = function(message, source, lineno, colno, error) {
  console.error('Global error:', message, error);
  return true;
};

3. 超时处理不当

错误现象:请求卡死导致页面卡顿

改进方法:设置合理的超时时间,并处理超时错误

// 设置超时时间
service.defaults.timeout = 5000;

// 处理超时错误
service.interceptors.response.use(response => {
  // 处理响应数据
  return response.data;
}, error => {
  if (error.code === 'ECONNABORTED') {
    console.error('Request timeout');
  }
  return Promise.reject(error);
});

4. 安全性隐患

风险点:明文传输敏感信息

解决方案:

  • 使用HTTPS
  • 对敏感数据进行加密
  • 添加请求签名验证
// 请求签名验证(服务端)
function verifySign(params, secret) {
  const expectedSign = generateSign(params, secret);
  const actualSign = params.sign;
  
  return expectedSign === actualSign;
}

十、最佳实践

1. 接口封装规范

  • 所有API接口统一归档
  • 使用枚举定义接口路径
  • 接口参数校验
  • 接口版本控制

2. 通用错误处理

  • 统一错误类型
  • 错误日志记录
  • 错误码映射
  • 错误提示规范
// 错误码映射
const errorMap = {
  400: '请求参数错误',
  401: '未授权',
  403: '禁止访问',
  404: '资源不存在',
  500: '服务器错误'
};

3. 安全性实践

  • 必要的请求头验证
  • 敏感数据加密传输
  • 请求签名验证
  • CORS安全配置
  • 防止CSRF攻击

4. 性能优化方案

  • 响应式数据缓存
  • 并发请求控制
  • 压缩数据传输
  • 异步加载优化
  • 资源预加载

十一、总结

在Vue2项目中使用axios进行网络请求,需要综合考虑多个方面:

  1. 核心原理:理解axios基于XMLHttpRequest的封装机制,掌握拦截器、并发请求等核心功能
  2. 实际应用:通过封装通用请求方法,统一接口处理,提高代码复用性
  3. 性能优化:通过缓存、并发控制、超时设置等手段提升性能
  4. 安全性:注意跨域、数据加密、请求签名等安全风险
  5. 错误处理:完善错误处理机制,避免页面崩溃
  6. 工程实践:遵循规范的代码组织方式,保持代码可维护性

在实际开发中,建议:

  • 使用统一的axios配置文件
  • 封装通用请求方法
  • 配置拦截器处理错误
  • 遵循安全实践规范
  • 定期进行性能优化

需要注意的是,虽然axios功能强大,但在以下场景可能不是最佳选择:

  • 需要复杂请求重试机制
  • 需要支持 WebSocket
  • 需要处理大量二进制数据
  • 需要更细粒度的控制

对于这些场景,可以考虑使用更专业的库如axios-multipart处理文件上传,axios-sockjs处理WebSocket,或使用fetch配合fetch-mock进行单元测试。

VUE , ios
最后修改于:2026年09月16日 02:10

评论已关闭

推荐阅读

AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日
python之plot()和subplot()画图
2024年11月26日
理解 DALL·E 2、Stable Diffusion 和 Midjourney 工作原理
2024年12月01日