Vue3的axios

Vue 3 中的 Axios 完全指南

本文档从零开始讲解在 Vue 3 项目里如何用 Axios 发 HTTP 请求:安装、基本用法、请求配置、响应与错误处理、封装实例、拦截器,以及在组件中的常见写法(列表、表单、加载与错误状态),配有大量示例,适合新手系统学习。


一、什么是 Axios?为什么在 Vue 里用它?

1.1 Axios 是什么?

Axios 是一个基于 PromiseHTTP 客户端,可以在浏览器和 Node.js 里发请求。
在 Vue 项目里,我们用它来请求后端接口:获取列表、提交表单、上传文件等。
它支持 GET、POST、PUT、PATCH、DELETE 等常见方法,支持 请求/响应拦截器取消请求超时 等,用起来比较方便。

1.2 和原生 fetch 的简单对比

  • fetch:浏览器自带,需自己处理 JSON、错误码、超时等。
  • Axios:第三方库,自动转 JSON、按状态码抛错、支持拦截器、API 更统一。
    在 Vue 项目里,用 Axios 做接口请求非常常见。

1.3 安装

在项目根目录执行:

npm install axios

或:

yarn add axios
pnpm add axios

安装完成后,在代码里 import axios 即可使用。


二、最基础的用法

2.1 GET 请求(无参)

import axios from 'axios'

axios.get('https://api.example.com/users').then((res) => {
  console.log(res.data)
}).catch((err) => {
  console.error(err)
})
  • axios.get(url) 返回一个 Promise
  • res响应对象,常用的是 res.data(后端返回的 JSON 会在这里)。
  • 请求失败(网络错误、4xx/5xx)会进入 catch

2.2 GET 请求(带查询参数)

写法一: 第二个参数传 params 对象,Axios 会自动拼成查询字符串。

axios.get('https://api.example.com/list', {
  params: {
    page: 1,
    size: 10,
    keyword: 'vue'
  }
}).then((res) => {
  console.log(res.data)
})

实际请求 URL 类似:https://api.example.com/list?page=1&size=10&keyword=vue

写法二: 自己把参数拼在 URL 里。

axios.get('https://api.example.com/list?page=1&size=10').then((res) => {
  console.log(res.data)
})

2.3 POST 请求(提交 JSON)

第三个参数是请求体,一般传对象,Axios 会按 JSON 发出去,并设置 Content-Type: application/json

axios.post('https://api.example.com/login', {
  username: 'admin',
  password: '123456'
}).then((res) => {
  console.log(res.data)
}).catch((err) => {
  console.error(err)
})

2.4 PUT / PATCH / DELETE

axios.put('https://api.example.com/user/1', { name: '新名字' })
axios.patch('https://api.example.com/user/1', { age: 20 })
axios.delete('https://api.example.com/user/1')

用法和 get/post 类似:url、可选的 config(params、headers 等)、post/put/patch 的第二个参数是 data


三、响应对象里有什么?

then 里拿到的 res 是 Axios 的响应对象,常用字段:

字段 含义
res.data 后端返回的响应体(通常是 JSON 解析后的对象或数组)
res.status HTTP 状态码(如 200、404、500)
res.statusText 状态文本(如 OK、Not Found)
res.headers 响应头对象

组件里用到的,绝大多数是 res.data

axios.get('/api/user').then((res) => {
  console.log(res.data)
  console.log(res.status)
})

四、错误处理(重要)

4.1 什么时候会进 catch?

  • 网络错误(断网、跨域被拦、超时等):会进 catcherr 里没有 responseresponse 不完整。
  • HTTP 状态码 4xx、5xx:Axios 默认也会抛错,会进 catch,此时 err.response 里有服务端返回的内容。

4.2 在 catch 里区分“网络错误”和“业务错误”

axios.get('/api/user').catch((err) => {
  if (err.response) {
    // 有 response 表示请求发到了服务器,服务器返回了 4xx/5xx
    console.log('状态码:', err.response.status)
    console.log('后端返回:', err.response.data)
  } else {
    // 没有 response:网络错误、超时、请求被取消等
    console.log('网络或其它错误', err.message)
  }
})

4.3 用 async/await 写(推荐)

async/await 时,用 try/catch 捕获错误:

async function fetchUser() {
  try {
    const res = await axios.get('/api/user')
    console.log(res.data)
  } catch (err) {
    if (err.response) {
      console.log('业务错误:', err.response.data)
    } else {
      console.log('网络错误:', err.message)
    }
  }
}

五、在 Vue 3 组件里发请求()

5.1 进入页面时请求列表(onMounted)

把请求写在 onMounted 里,用 ref 存列表和加载/错误状态,模板里根据状态显示“加载中”“错误”“列表”:

<template>
  <div>
    <p v-if="loading">加载中...</p>
    <p v-else-if="error">{{ error }}</p>
    <ul v-else>
      <li v-for="item in list" :key="item.id">{{ item.name }}</li>
    </ul>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'

const list = ref([])
const loading = ref(true)
const error = ref('')

onMounted(async () => {
  try {
    loading.value = true
    error.value = ''
    const res = await axios.get('https://api.example.com/list')
    list.value = res.data
  } catch (err) {
    error.value = err.response?.data?.message || err.message || '请求失败'
  } finally {
    loading.value = false
  }
})
</script>
  • loading:请求前 true,请求结束(成功或失败)在 finally 里设为 false。
  • error:失败时把提示文案赋给 error,模板里用 v-else-if=”error” 显示。
  • list:成功时 list.value = res.data(按你后端实际结构可能是 res.data.list 等)。

5.2 点击按钮再请求(如提交表单)

<template>
  <form @submit.prevent="onSubmit">
    <input v-model="form.username" placeholder="用户名" />
    <input v-model="form.password" type="password" placeholder="密码" />
    <button type="submit" :disabled="submitting">提交</button>
  </form>
</template>

<script setup>
import { ref, reactive } from 'vue'
import axios from 'axios'

const form = reactive({ username: '', password: '' })
const submitting = ref(false)

async function onSubmit() {
  try {
    submitting.value = true
    const res = await axios.post('/api/login', form)
    console.log('成功', res.data)
  } catch (err) {
    console.error(err.response?.data || err.message)
  } finally {
    submitting.value = false
  }
}
</script>
  • :disabled=”submitting” 防止重复提交。
  • submittingfinally 里统一设为 false。

六、请求配置(baseURL、headers、timeout)

6.1 常用配置项

发请求时,第二个参数是 config 对象(GET 时第二个参数就是 config;POST 时第二个是 data,第三个是 config):

axios.get('/api/list', {
  params: { page: 1 },
  headers: { 'X-Token': 'xxx' },
  timeout: 5000
})

axios.post('/api/login', { username: 'a', password: 'b' }, {
  headers: { 'Content-Type': 'application/json' },
  timeout: 5000
})
配置 含义
params 查询参数(GET 时常用)
data 请求体(POST/PUT/PATCH 常用)
headers 请求头
timeout 超时时间(毫秒)
baseURL 基础 URL,和请求 url 拼在一起(见下一小节)

6.2 创建实例(统一 baseURL 和 timeout)

项目里接口通常有统一的基础地址超时时间,建议用 axios.create 创建一个实例,后面都用这个实例发请求:

// request.js 或 api/request.js
import axios from 'axios'

const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

export default request

使用:

import request from './request'

request.get('/users').then((res) => console.log(res.data))
request.post('/login', { username: 'a', password: 'b' })
  • request.get(‘/users’) 实际请求:https://api.example.com/users
  • 若后端在本地:可设 baseURL: ‘/api’,再在开发环境用代理把 /api 转到真实地址(见 Vite/Webpack 配置)。

七、拦截器(统一加 token、统一处理错误)

7.1 请求拦截器(例如统一加 Token)

在请求发出去之前统一加 token 或其它 header:

import axios from 'axios'

const request = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (err) => {
    return Promise.reject(err)
  }
)

export default request

之后所有用 request 发的请求,都会自动带上 Authorization 头(若有 token)。

7.2 响应拦截器(统一处理 401、统一取 data)

在收到响应后、返回到 then 之前,可以统一处理状态码或统一只返回 data

request.interceptors.response.use(
  (res) => {
    return res.data
  },
  (err) => {
    if (err.response?.status === 401) {
      localStorage.removeItem('token')
      window.location.href = '/login'
    }
    return Promise.reject(err)
  }
)
  • 成功时return res.data,这样在业务里 await request.get(‘/users’) 拿到的直接就是 data,不用再写 res.data
  • 失败时:401 可跳转登录;其它错误继续 Promise.reject(err),由业务里 catch 处理。

八、完整示例:封装 request + 在组件里用

8.1 封装 request(baseURL + 请求/响应拦截器)

// src/api/request.js
import axios from 'axios'

const request = axios.create({
  baseURL: import.meta.env.VITE_API_BASE || '/api',
  timeout: 10000
})

request.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = `Bearer ${token}`
    }
    return config
  },
  (err) => Promise.reject(err)
)

request.interceptors.response.use(
  (res) => res.data,
  (err) => {
    if (err.response?.status === 401) {
      localStorage.removeItem('token')
      window.location.href = '/login'
    }
    return Promise.reject(err)
  }
)

export default request

(若用 Vite,环境变量用 import.meta.env.VITE_XXX;baseURL 也可直接写字符串。)

8.2 封装接口函数(按模块)

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

export function getUser() {
  return request.get('/user')
}

export function login(data) {
  return request.post('/login', data)
}

8.3 在组件里使用

<template>
  <div>
    <p v-if="loading">加载中...</p>
    <p v-else-if="error">{{ error }}</p>
    <div v-else>{{ user?.name }}</div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { getUser } from '@/api/user'

const user = ref(null)
const loading = ref(true)
const error = ref('')

onMounted(async () => {
  try {
    const data = await getUser()
    user.value = data
  } catch (err) {
    error.value = err.response?.data?.message || '加载失败'
  } finally {
    loading.value = false
  }
})
</script>

因为响应拦截器里 return res.data,所以 getUser() 的返回值就是 data


九、常见场景示例

9.1 分页列表(params + 翻页)

const list = ref([])
const page = ref(1)
const total = ref(0)

async function loadList() {
  try {
    const data = await request.get('/list', {
      params: { page: page.value, size: 10 }
    })
    list.value = data.list
    total.value = data.total
  } catch (err) {
    console.error(err)
  }
}

function nextPage() {
  page.value++
  loadList()
}

9.2 提交表单并跳转

async function onSubmit() {
  try {
    const data = await request.post('/register', form)
    alert('注册成功')
    router.push('/login')
  } catch (err) {
    alert(err.response?.data?.message || '注册失败')
  }
}

9.3 删除并刷新列表

async function remove(id) {
  if (!confirm('确定删除?')) return
  try {
    await request.delete(`/item/${id}`)
    await loadList()
  } catch (err) {
    alert('删除失败')
  }
}

十、易错点与注意点

10.1 接口返回结构要对应

后端可能是 { data: { list: [] } }{ list: [] }res.data 或拦截器返回后,要按实际结构取:res.data.listdata.list

10.2 跨域与 baseURL

浏览器有同源策略,前端 http://localhost:5173 请求 https://api.xxx.com 会跨域。
开发时常用 代理:前端请求 /api/xxx,由 Vite/Webpack 转发到真实域名;此时 baseURL 可设为 ‘/api’

10.3 别忘了 loading / error 和 finally

请求前设 loading = true,在 finally 里设 loading = false,避免请求一直转圈;错误信息赋给 error 并在模板里展示,体验更好。


十一、速查表

需求 写法
GET axios.get(url, { params })request.get(url, { params })
POST axios.post(url, data)
拿响应体 res.data(若拦截器 return res.data,则直接拿返回值)
错误处理 catchtry/catch,用 err.response?.statuserr.response?.data
统一 baseURL/timeout axios.create({ baseURL, timeout })
统一加 token 请求拦截器里改 config.headers.Authorization
统一处理 401 响应拦截器里判断 err.response?.status === 401 再跳转登录

十二、学习建议

  1. 先会 get/postres.datacatch 里区分 err.response 有无。
  2. 在组件里用 ref 存列表/loading/error,在 onMounted 或按钮事件里 async/await + try/catch
  3. 项目里用 axios.create 建实例,配好 baseURL拦截器,接口按模块封装成函数再在组件里调用。

把本文档的“封装 request + 组件里请求列表”自己敲一遍,再改成你的接口地址和返回结构,会掌握得更牢。祝你学习顺利。

发表评论