axios


在前端开发中,HTTP 请求是与后端交互的核心环节。axios 作为当前最流行的 HTTP 客户端之一,凭借其简洁的 API、完善的功能和良好的兼容性,成为 Vue、React 等框架的首选请求工具。本文将从基础入门到高级实战,带你全方位掌握 axios 的使用技巧。

一、入门篇:认识 axios 并实现基础请求

1.1 什么是 axios?

axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境,主要特点包括:

  • 支持 GET、POST 等所有 HTTP 请求方法

  • 拦截请求和响应

  • 自动转换 JSON 数据

  • 取消请求

  • 超时设置

  • 错误处理

  • 客户端防御 XSRF 攻击

1.2 安装与引入

方式 1:CDN 引入(快速测试)

<!-- 开发版(含调试信息) -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<!-- 生产版(压缩优化) -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script>

方式 2:npm/yarn 安装(项目开发)

# npm
npm install axios --save

# yarn
yarn add axios

在项目中引入:

// ES6模块
import axios from 'axios';

// CommonJS
const axios = require('axios');

1.3 基础请求实现

1.3.1 GET 请求(获取数据)

无参数请求

// 方式1:直接传入URL
axios.get('https://api.example.com/users')
  .then(response => {
    console.log('请求成功:', response.data)
  }).catch(error => {
    console.error('请求失败:', error)
  })

// 方式2:使用async/await(推荐,代码更简洁)
async function getUserList () {
  try {
    const response = await axios.get('https://api.example.com/users')
    console.log('用户列表:', response.data)
    return response.data
  } catch (error) {
    console.error('获取用户失败:', error.message)
    throw error // 如需上层处理,可抛出错误
  }
}

带参数请求

// 方式1:URL拼接参数
axios.get('https://api.example.com/users?id=123')

// 方式2:通过params配置(推荐,自动编码特殊字符)
axios.get('https://api.example.com/users', {
  params: {
    id: 123,
    status: 'active',
    page: 1,
    size: 10
  }
}).then(response => console.log(response.data)).catch(error => console.error(error))

1.3.2 POST 请求(提交数据)

主要用于提交表单、创建资源等场景,常用application/json格式(默认):

async function createUser () {
  const userData = {
    name: '张三',
    age: 25,
    email: 'zhangsan@example.com'
  }

  try {
    const response = await axios.post('https://api.example.com/users', userData, {
      headers: {
        'Content-Type': 'application/json' // 默认已设置,可省略
      }
    })
    console.log('用户创建成功:', response.data)
  } catch (error) {
    console.error('创建用户失败:', error)
  }
}

表单提交(application/x-www-form-urlencoded)

// 方式1:手动转换
import qs from 'qs' // 需要安装qs:npm install qs

async function submitForm () {
  const formData = { username: 'admin', password: '123456' }
  const response = await axios.post(
    'https://api.example.com/login',
    qs.stringify(formData), // 转换为key=value格式
    { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
  )
  console.log('登录成功:', response.data)
}

// 方式2:使用FormData(文件上传常用)
async function uploadFile (file) {
  const formData = new FormData()
  formData.append('file', file)
  formData.append('description', '文档上传')
  const response = await axios.post(
    'https://api.example.com/upload',
    formData // FormData会自动设置Content-Type
  )
  console.log('上传成功:', response.data)
}

1.4 响应结构解析

axios 请求成功后返回的response对象包含以下核心属性:

{
  data: { }, // 后端返回的响应数据(自动解析JSON)
  status: 200, // HTTP状态码(200=成功,404=未找到,500=服务器错误等)
  statusText: 'OK', // 状态文本描述
  headers: { }, // 响应头信息
  config: { }, // 本次请求的配置信息(URL、方法、参数等)
  request: { } // 原生请求对象(浏览器中是XMLHttpRequest,Node.js中是http.ClientRequest)
}

二、进阶篇:核心功能实战

2.1 请求拦截器与响应拦截器

拦截器可对请求 / 响应进行统一处理,如添加 token、统一错误提示等,避免重复代码。

2.1.1 请求拦截器(处理请求前逻辑)

// 创建请求拦截器
axios.interceptors.request.use(
  // 请求成功拦截(配置修改)
  config => {
    // 1. 添加Token(登录后常用)
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }

    // 2. 设置超时时间(全局统一)
    config.timeout = 10000 // 10秒超时

    // 3. 统一添加基础路径(也可通过defaults设置)
    config.baseURL = 'https://api.example.com'
    return config
  },

  // 请求错误拦截(如参数错误)
  error => {
    console.error('请求配置错误:', error)
    return Promise.reject(error) // 必须返回rejected状态的Promise
  }
)

2.1.2 响应拦截器(处理响应后逻辑)

// 创建响应拦截器
axios.interceptors.response.use(
  // 响应成功拦截(状态码2xx/3xx)
  response => {
    // 可对响应数据进行统一处理(如剥离外层包装)
    // 例:后端返回格式为 { code: 200, message: "成功", data: {} }
    if (response.data.code === 200) {
      return response.data.data // 直接返回核心数据,简化上层使用
    }
    return response.data
  },

  // 响应错误拦截(状态码4xx/5xx或网络错误)
  error => {
    // 1. 处理网络错误
    if (!error.response) {
      alert('网络异常,请检查网络连接!')
      return Promise.reject(new Error('网络错误'))
    }

    // 2. 处理HTTP错误状态码
    const status = error.response.status
    switch (status) {
      case 401: // 未授权(Token过期或无效)
        alert('登录已过期,请重新登录!')
        localStorage.removeItem('token') // 清除无效Token
        window.location.href = '/login' // 跳转登录页
        break

      case 403: // 权限不足
        alert('您没有操作权限!')
        break

      case 404: // 资源未找到
        alert('请求的资源不存在!')
        break

      case 500: // 服务器错误
        alert('服务器内部错误,请稍后重试!')
        break

      default:
        alert(`请求错误(${status}`)
    }
    return Promise.reject(error)
  }
)

2.1.3 移除拦截器

如需临时禁用拦截器,可保存拦截器 ID 并移除:

// 保存请求拦截器ID
const requestInterceptor = axios.interceptors.request.use(config => config)

// 移除请求拦截器
axios.interceptors.request.eject(requestInterceptor)

// 同理移除响应拦截器
const responseInterceptor = axios.interceptors.response.use(res => res)

axios.interceptors.response.eject(responseInterceptor)

2.2 并发请求处理

当需要同时发送多个请求并等待所有请求完成后再处理时,可使用axios.allaxios.spread(或 ES6 的Promise.all)。

方式 1:axios.all + axios.spread

// 定义两个请求
const request1 = axios.get('/users')
const request2 = axios.get('/posts')

// 并发执行
axios.all([request1, request2]).then(
  axios.spread((usersResponse, postsResponse) => {
    // 所有请求成功后执行
    console.log('用户数据:', usersResponse.data)
    console.log('文章数据:', postsResponse.data)
  })
).catch(error => {
  console.error('至少一个请求失败:', error)
})

方式 2:Promise.all(更通用,推荐)

async function fetchMultipleData () {
  try {
    const [usersData, postsData] = await Promise.all([
      axios.get('/users'),
      axios.get('/posts')
    ])
    console.log('用户数据:', usersData.data)
    console.log('文章数据:', postsData.data)
  } catch (error) {
    console.error('并发请求失败:', error)
  }
}

2.3 取消请求

在某些场景下(如用户快速切换页面、搜索框输入防抖),需要取消未完成的请求,避免无效请求占用资源。

方式 1:使用 CancelToken(旧版,Axios < 0.22.0)

// 创建取消令牌生成器
const CancelToken = axios.CancelToken;
let cancel; // 用于保存取消函数

// 发送请求并绑定取消令牌
axios
  .get("/users", {
    cancelToken: new CancelToken(function executor(c) {
      cancel = c; // 将取消函数赋值给外部变量
    }),
  })
  .then((res) => console.log(res.data))
  .catch((error) => {
    if (axios.isCancel(error)) {
      console.log("请求已取消:", error.message);
    } else {
      console.error("请求失败:", error);
    }
  });

// 取消请求(如用户点击“取消”按钮时)
cancel("用户主动取消请求");

方式 2:使用 AbortController(新版,Axios ≥ 0.22.0,推荐)

AbortController 是浏览器原生 API,更标准且支持取消多个请求:

// 创建控制器
const controller = new AbortController();
const signal = controller.signal; // 获取信号对象

// 发送请求(绑定信号)
axios
  .get("/users", { signal })
  .then((res) => console.log(res.data))
  .catch((error) => {
    if (error.name === "CanceledError") {
      console.log("请求已取消");
    } else {
      console.error("请求失败:", error);
    }
  });

// 取消请求
controller.abort();

// 取消多个请求(共用同一个signal)
axios.get("/posts", { signal }); // 此请求也会被上面的abort()取消

三、高级篇:深度定制与最佳实践

3.1 创建自定义 axios 实例

当项目中存在多个后端服务(如 API 服务、文件服务),或需要不同的请求配置时,可创建多个自定义实例,避免全局配置冲突。

// 创建自定义实例
const apiInstance = axios.create({
  baseURL: "https://api.example.com", // 基础路径
  timeout: 15000, // 超时时间
  headers: {
    "Content-Type": "application/json",
    "X-Request-From": "web", // 自定义请求头(标识请求来源)
  },
});

// 为自定义实例添加拦截器
apiInstance.interceptors.request.use((config) => {
  const token = localStorage.getItem("token");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// 使用自定义实例发送请求
async function getArticle(id) {
  try {
    const response = await apiInstance.get(`/articles/${id}`);
    return response.data;
  } catch (error) {
    console.error("获取文章失败:", error);
  }
}

// 再创建文件服务实例(不同配置)
const fileInstance = axios.create({
  baseURL: "https://file.example.com",
  timeout: 30000, // 文件上传超时时间更长
  headers: { "Content-Type": "multipart/form-data" },
});

3.2 错误处理最佳实践

3.2.1 错误分类处理

axios 的错误主要分为三类,需针对性处理:

  1. 网络错误:无响应(如断网、跨域错误)

  2. HTTP 错误:响应状态码 4xx/5xx

  3. 业务错误:状态码 200,但后端返回错误(如code: 5001

async function requestWithErrorHandle(url, config = {}) {
  try {
    const response = await axios(url, config);

    // 处理业务错误(假设后端返回 { code, message, data })
    if (response.data.code !== 200) {
      throw new Error(`业务错误:${response.data.message}`);
    }

    return response.data.data;
  } catch (error) {
    // 1. 网络错误
    if (!error.response) {
      console.error("网络错误:", error.message);
      return { success: false, message: "网络异常,请检查连接" };
    }

    // 2. HTTP错误
    const { status, statusText } = error.response;
    console.error(`HTTP错误:${status} ${statusText}`);
    let message = `请求失败(${status}`;
    if (status === 401) message = "登录已过期,请重新登录";
    if (status === 403) message = "权限不足,无法操作";
    if (status === 500) message = "服务器繁忙,请稍后重试";
    // 3. 业务错误(已在try中抛出)
    if (error.message.startsWith("业务错误:")) {
      message = error.message.slice(6);
    }
    return { success: false, message };
  }
}

3.2.2 错误重试机制

对于偶发性错误(如网络波动、服务器临时不可用),可实现自动重试功能:

// 带重试的请求函数
async function requestWithRetry(url, config = {}, retryCount = 2) {
  try {
    return await axios(url, config);
  } catch (error) {
    // 仅对5xx服务器错误和网络错误重试
    if (
      retryCount > 0 &&
      (!error.response ||
        (error.response.status >= 500 && error.response.status < 600))
    ) {
      console.log(`请求失败,正在重试(剩余${retryCount}次)`);

      // 重试前等待1秒(避免频繁重试)
      await new Promise((resolve) => setTimeout(resolve, 1000));
      return requestWithRetry(url, config, retryCount - 1);
    }

    // 重试次数用尽或非可重试错误,抛出错误
    throw error;
  }
}

// 使用
requestWithRetry("/data", { method: "GET" })
  .then((res) => console.log(res.data))
  .catch((error) => console.error("最终请求失败:", error));

3.3 与 TypeScript 结合(类型安全)

在 TS 项目中使用 axios 时,可通过接口定义请求参数和响应数据的类型,提升代码可维护性。

// 1. 定义响应数据类型
interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

// 2. 定义业务数据类型
interface User {
  id: number;
  name: string;
  email: string;
  status: "active" | "inactive";
}

// 3. 带类型的请求函数
async function getUserById(id: number): Promise<User> {
  const response: ApiResponse<User> = await axios.get(`/users/${id}`);
  if (response.code !== 200) {
    throw new Error(`获取用户失败:${response.message}`);
  }
  return response.data;
}

// 4. 使用(自动提示类型)
getUserById(123).then((user) => {
  console.log(user.name); // 类型安全,不会报错
});

3.4 配置优先级

axios 的配置有三个层级,优先级从高到低为:

  1. 请求配置(单次请求时传入的 config)

  2. 实例配置(create 创建实例时的 config)

  3. 全局默认配置(axios.defaults)

// 1. 全局默认配置
axios.defaults.baseURL = "https://default.example.com";
axios.defaults.timeout = 5000;

// 2. 实例配置(覆盖全局默认)
const instance = axios.create({
  baseURL: "https://instance.example.com",

  timeout: 10000,
});

// 3. 请求配置(覆盖实例配置)
instance.get("/data", {
  timeout: 15000, // 最终生效的超时时间为15000ms
});

四、总结与最佳实践

  1. 优先使用 async/await:相比.then (),代码更简洁,错误处理更直观

  2. 统一拦截器管理:在项目入口处配置全局拦截器,避免重复代码

  3. 创建自定义实例:多服务场景下,用实例隔离不同配置

  4. 合理设置超时:根据业务场景设置(普通请求 10s,文件上传 30s+)

  5. 取消无效请求:搜索、分页切换时取消前一次请求,减少资源浪费

  6. 完善错误处理:区分网络错误、HTTP 错误、业务错误,给用户友好提示

  7. 类型安全(TS 项目):定义请求 / 响应类型,提升代码可维护性

axios 作为前端请求的核心工具,掌握其从基础到高级的用法,能大幅提升接口交互的效率和稳定性。建议在实际项目中结合业务场景灵活运用,形成适合自身项目的请求封装方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值