大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
数据请求
这一课你将能做到
- 用原生
fetch发送 HTTP 请求 - 用
axios发送请求并配置拦截器 - 在组件中管理 loading 和 error 状态
- 封装通用的
useFetch组合式函数
为什么要学
前端不是孤岛,数据都在后端服务器上。不会发请求,你的页面只能展示写死的数据。掌握数据请求,才能做真正的「动态应用」。
人话:数据请求就像「点外卖」。你(前端)告诉外卖平台(后端 API)要什么,平台做好后送给你。过程中你要等(loading),可能送错(error),送到后开吃(渲染数据)。
先建立图像
<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
const loading = ref(true)
const error = ref(null)
onMounted(async () => {
try {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
users.value = await res.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
})
</script>
<template>
<p v-if="loading">加载中...</p>
<p v-else-if="error">出错了:{{ error }}</p>
<ul v-else>
<li v-for="u in users" :key="u.id">{{ u.name }}</li>
</ul>
</template>
跟着做
步骤 1:原生 fetch 基础
// GET 请求
const res = await fetch('https://api.example.com/users')
const data = await res.json()
// POST 请求
const res = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: '张三', age: 25 })
})
const data = await res.json()
步骤 2:axios 安装与使用
npm install axios
import axios from 'axios'
// GET
const res = await axios.get('https://api.example.com/users')
console.log(res.data) // axios 自动解析 JSON
// POST
const res = await axios.post('https://api.example.com/users', {
name: '张三'
})
步骤 3:axios 拦截器
// api/request.js
import axios from 'axios'
const request = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000
})
// 请求拦截器:自动加 token
request.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
})
// 响应拦截器:统一处理错误
request.interceptors.response.use(
res => res.data,
err => {
if (err.response?.status === 401) {
// 跳转登录
router.push('/login')
}
return Promise.reject(err)
}
)
export default request
步骤 4:组件中管理请求状态
<script setup>
import { ref } from 'vue'
import request from '../api/request'
const data = ref(null)
const loading = ref(false)
const error = ref(null)
async function fetchData() {
loading.value = true
error.value = null
try {
data.value = await request.get('/users')
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
}
</script>
步骤 5:封装 useFetch
// composables/useFetch.js
import { ref, toValue, watchEffect } from 'vue'
export function useFetch(url) {
const data = ref(null)
const loading = ref(true)
const error = ref(null)
watchEffect(async () => {
loading.value = true
error.value = null
try {
const res = await fetch(toValue(url))
data.value = await res.json()
} catch (e) {
error.value = e.message
} finally {
loading.value = false
}
})
return { data, loading, error }
}
<script setup>
import { useFetch } from '../composables/useFetch'
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users')
</script>
讲清楚要点
- fetch 是浏览器原生 API:不需要安装,但功能基础(不自动解析 JSON、不自动处理错误状态码)。
- axios 是功能更全的 HTTP 库:自动转换 JSON、拦截器、取消请求、并发请求等。
- loading 和 error 状态必须管理:给用户明确的反馈,避免「点了没反应」。
- 拦截器是统一处理的利器:token 注入、错误码处理、 loading 全局管理。
- useFetch 是组合式函数的典范:把请求逻辑封装成可复用的函数。
你可能会懵的地方
-
fetch 和 axios 怎么选? 小项目用 fetch 即可;需要拦截器、取消请求、进度监控用 axios。
-
为什么 fetch 不自动 reject 404? fetch 只在网络故障时 reject,HTTP 错误状态码(404、500)也 resolve,需要手动检查
res.ok。 -
组件销毁后请求回来了怎么办? 用 AbortController 取消请求,或在回调里检查组件是否还存活。
-
useFetch 里为什么要 watchEffect? 让 url 支持 ref,url 变化时自动重新请求。
-
怎么实现请求重试? 在 catch 里递归调用,或封装 retry 逻辑。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| fetch 不检查 res.ok | 404/500 也当成功处理 | if (!res.ok) throw new Error(...) |
| 在 try 块里不 await | 错误不会被 catch 捕获 | 所有异步操作前加 await |
| 组件销毁后 setState | 控制台警告,内存泄漏 | 用 AbortController 取消 |
| 每个组件都写一遍 loading/error | 代码冗余 | 封装 useFetch 或全局拦截器 |
| 把 token 硬编码在代码里 | 安全风险 | 从 localStorage 或环境变量读取 |
卡点急救
- 跨域报错:后端配置 CORS,或开发环境配置代理(vite.config.js 的 server.proxy)。
- 请求发出去了但数据不更新:检查是否给 ref 赋值,检查响应式数据是否正确。
- 拦截器不生效:确认拦截器代码在请求发送前执行,确认返回 config。
面试常问
-
fetch 和 axios 的区别? fetch 原生、轻量,但功能基础;axios 功能全(拦截器、取消、进度),但体积大。
-
怎么取消一个请求? fetch 用 AbortController;axios 用 CancelToken 或 AbortController(v0.22+)。
-
什么是组合式函数(Composables)? 利用 Vue 组合式 API 封装可复用逻辑的函数,以
use开头,如useFetch、useLocalStorage。
自测三问
fetch在什么情况下会 reject?- axios 的请求拦截器和响应拦截器分别适合做什么?
- 封装
useFetch有什么好处?
小结一句话
数据请求是前后端的桥梁,fetch/axios 发送请求,拦截器统一处理,loading/error 状态提升体验,useFetch 封装复用逻辑,掌握它们就能与后端高效协作。
延伸
- Axios 官方文档
- 下一课:UI 与插件——Element Plus、Tailwind CSS、自定义指令。