Skip to content

Axios 网络请求

Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。它是 Vue 项目中最常用的网络请求库之一。

为什么使用 Axios?

  • 支持 Promise API:使用现代化的 Promise 语法
  • 拦截器:可以在请求和响应前后添加拦截器
  • 自动转换 JSON 数据:自动将响应数据转换为 JSON 格式
  • 请求取消:支持取消正在进行的请求
  • 超时处理:可以设置请求超时时间
  • 错误处理:提供详细的错误信息

Axios 安装

bash
npm install axios

基本使用

发送 GET 请求

javascript
import axios from 'axios'

// 基本 GET 请求
axios.get('https://api.example.com/users')
  .then(response => {
    console.log(response.data)
  })
  .catch(error => {
    console.error('请求失败:', error)
  })

// 带参数的 GET 请求
axios.get('https://api.example.com/users', {
  params: {
    page: 1,
    limit: 10
  }
})
  .then(response => {
    console.log(response.data)
  })
  .catch(error => {
    console.error('请求失败:', error)
  })

发送 POST 请求

javascript
import axios from 'axios'

// 发送 POST 请求
axios.post('https://api.example.com/users', {
  name: '张三',
  age: 20,
  email: 'zhangsan@example.com'
})
  .then(response => {
    console.log(response.data)
  })
  .catch(error => {
    console.error('请求失败:', error)
  })

发送其他类型的请求

javascript
import axios from 'axios'

// PUT 请求
axios.put('https://api.example.com/users/1', {
  name: '李四',
  age: 21
})

// DELETE 请求
axios.delete('https://api.example.com/users/1')

// PATCH 请求
axios.patch('https://api.example.com/users/1', {
  name: '王五'
})

封装请求工具类

为了更好地管理 API 请求,我们可以封装一个请求工具类。

创建 axios 实例

javascript
// utils/request.js
import axios from 'axios'

// 创建 axios 实例
const request = axios.create({
  baseURL: 'https://api.example.com', // 基础 URL
  timeout: 10000, // 超时时间
  headers: {
    'Content-Type': 'application/json'
  }
})

export default request

添加请求拦截器

javascript
// utils/request.js
import axios from 'axios'

const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
})

// 请求拦截器
request.interceptors.request.use(
  config => {
    // 在发送请求之前做些什么
    // 例如,添加 token
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    // 对请求错误做些什么
    console.error('请求错误:', error)
    return Promise.reject(error)
  }
)

export default request

添加响应拦截器

javascript
// utils/request.js
import axios from 'axios'

const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
})

// 请求拦截器
request.interceptors.request.use(
  config => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  error => {
    console.error('请求错误:', error)
    return Promise.reject(error)
  }
)

// 响应拦截器
request.interceptors.response.use(
  response => {
    // 对响应数据做点什么
    return response.data
  },
  error => {
    // 对响应错误做点什么
    if (error.response) {
      // 服务器返回错误状态码
      switch (error.response.status) {
        case 401:
          // 未授权,跳转到登录页
          window.location.href = '/login'
          break
        case 403:
          // 禁止访问
          console.error('禁止访问')
          break
        case 404:
          // 资源不存在
          console.error('资源不存在')
          break
        case 500:
          // 服务器错误
          console.error('服务器错误')
          break
        default:
          console.error('请求失败')
      }
    } else if (error.request) {
      // 请求已发送但没有收到响应
      console.error('网络错误,无法连接到服务器')
    } else {
      // 请求配置出错
      console.error('请求配置错误:', error.message)
    }
    return Promise.reject(error)
  }
)

export default request

使用封装的请求工具

javascript
// api/user.js
import request from '../utils/request'

export const getUserList = (params) => {
  return request({
    url: '/users',
    method: 'get',
    params
  })
}

export const getUserById = (id) => {
  return request({
    url: `/users/${id}`,
    method: 'get'
  })
}

export const createUser = (data) => {
  return request({
    url: '/users',
    method: 'post',
    data
  })
}

export const updateUser = (id, data) => {
  return request({
    url: `/users/${id}`,
    method: 'put',
    data
  })
}

export const deleteUser = (id) => {
  return request({
    url: `/users/${id}`,
    method: 'delete'
  })
}

跨域问题解决方案

什么是跨域?

跨域是指浏览器禁止从一个域名的网页去请求另一个域名的资源。这是浏览器的同源策略限制。

跨域解决方案

1. 后端设置 CORS

后端服务器可以设置 Access-Control-Allow-Origin 响应头来允许跨域请求。

javascript
// Express 示例
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*')
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  
  if (req.method === 'OPTIONS') {
    return res.status(200).end()
  }
  
  next()
})

2. 前端使用代理

在开发环境中,可以使用 Vite 的代理功能来解决跨域问题。

javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

然后,前端请求可以使用 /api 前缀:

javascript
// utils/request.js
const request = axios.create({
  baseURL: '/api', // 使用代理路径
  timeout: 10000,
  headers: {
    'Content-Type': 'application/json'
  }
})

实战示例

用户管理系统

vue
<template>
  <div>
    <h2>用户管理</h2>
    
    <!-- 添加用户 -->
    <div class="add-user">
      <h3>添加用户</h3>
      <input v-model="newUser.name" placeholder="姓名">
      <input v-model.number="newUser.age" type="number" placeholder="年龄">
      <input v-model="newUser.email" placeholder="邮箱">
      <button @click="addUser" :disabled="loading">添加</button>
    </div>
    
    <!-- 用户列表 -->
    <div class="user-list">
      <h3>用户列表</h3>
      <div v-if="loading" class="loading">加载中...</div>
      <div v-else-if="error" class="error">{{ error }}</div>
      <ul v-else>
        <li v-for="user in users" :key="user.id">
          <div>{{ user.name }} ({{ user.age }}) - {{ user.email }}</div>
          <button @click="editUser(user)">编辑</button>
          <button @click="deleteUser(user.id)">删除</button>
        </li>
      </ul>
    </div>
    
    <!-- 编辑用户 -->
    <div v-if="editingUser" class="edit-user">
      <h3>编辑用户</h3>
      <input v-model="editingUser.name" placeholder="姓名">
      <input v-model.number="editingUser.age" type="number" placeholder="年龄">
      <input v-model="editingUser.email" placeholder="邮箱">
      <button @click="updateUser" :disabled="loading">更新</button>
      <button @click="cancelEdit">取消</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { getUserList, createUser, updateUser, deleteUser } from './api/user'

const users = ref([])
const loading = ref(false)
const error = ref('')
const newUser = ref({ name: '', age: 0, email: '' })
const editingUser = ref(null)

// 获取用户列表
async function fetchUsers() {
  loading.value = true
  error.value = ''
  try {
    users.value = await getUserList()
  } catch (err) {
    error.value = '获取用户列表失败'
    console.error(err)
  } finally {
    loading.value = false
  }
}

// 添加用户
async function addUser() {
  if (!newUser.value.name || !newUser.value.email) {
    error.value = '请填写姓名和邮箱'
    return
  }
  
  loading.value = true
  error.value = ''
  try {
    await createUser(newUser.value)
    await fetchUsers()
    // 清空表单
    newUser.value = { name: '', age: 0, email: '' }
  } catch (err) {
    error.value = '添加用户失败'
    console.error(err)
  } finally {
    loading.value = false
  }
}

// 编辑用户
function editUser(user) {
  editingUser.value = { ...user }
}

// 更新用户
async function updateUser() {
  if (!editingUser.value.name || !editingUser.value.email) {
    error.value = '请填写姓名和邮箱'
    return
  }
  
  loading.value = true
  error.value = ''
  try {
    await updateUser(editingUser.value.id, editingUser.value)
    await fetchUsers()
    editingUser.value = null
  } catch (err) {
    error.value = '更新用户失败'
    console.error(err)
  } finally {
    loading.value = false
  }
}

// 取消编辑
function cancelEdit() {
  editingUser.value = null
}

// 删除用户
async function deleteUser(id) {
  if (!confirm('确定要删除这个用户吗?')) {
    return
  }
  
  loading.value = true
  error.value = ''
  try {
    await deleteUser(id)
    await fetchUsers()
  } catch (err) {
    error.value = '删除用户失败'
    console.error(err)
  } finally {
    loading.value = false
  }
}

// 组件挂载时获取用户列表
onMounted(() => {
  fetchUsers()
})
</script>

<style scoped>
.add-user, .edit-user {
  margin-bottom: 20px;
  padding: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.user-list {
  margin-top: 20px;
}

.loading, .error {
  padding: 10px;
  margin: 10px 0;
}

.error {
  color: red;
  background-color: #ffe6e6;
  border: 1px solid #ffcccc;
  border-radius: 4px;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  padding: 10px;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

input {
  margin-right: 10px;
  padding: 5px;
}

button {
  margin-right: 5px;
  padding: 5px 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background-color: #f0f0f0;
  cursor: pointer;
}

button:hover {
  background-color: #e0e0e0;
}

button:disabled {
  background-color: #f0f0f0;
  cursor: not-allowed;
  color: #999;
}
</style>

通过本章的学习,我们掌握了 Axios 的基本使用方法,包括发送各种类型的请求、封装请求工具类、添加拦截器以及解决跨域问题等。Axios 是 Vue 项目中处理网络请求的重要工具,它提供了简洁的 API 和强大的功能,帮助我们更高效地与后端 API 进行交互。

© 2026 编程马·菜鸟教程 版权所有