入门
本篇带你从安装到「请求 → 自动解析 → 传 body → 处理错误 → 加 query / baseURL」跑通 ofetch 的主线。版本基线 ofetch 1.x。对比对象:axios(XHR、体积大)、ky(同为 fetch 封装)、原生 fetch。
速查
- 安装:
npm install ofetch - 导入:
import { ofetch } from 'ofetch'(具名导出;别名$fetch指向同一实例) - 取数据:
const data = await ofetch('/api/user')→ 已解析的对象,无需.json() - 传 body:
ofetch('/api', { method: 'POST', body: { name: 'foo' } })→ 自动 JSON 化 - 加 query:
ofetch('/api/list', { query: { page: 2 } })(底层 ufo,可与 URL 已有 query 合并) - 完整响应:
ofetch.raw(url)→ 含status/headers,数据在response._data - 错误:非 2xx 自动抛 FetchError,错误体在
error.data,状态码在error.status - 实例:
const api = ofetch.create({ baseURL: '/api' }) - ⚠️ 写方法(POST 等)默认 retry=0;GET/HEAD 默认 retry=1
- ⚠️ Nuxt 的
$fetch就是 ofetch
一、ofetch 是什么
官方一句话定位:「A better fetch API. Works on node, browser and workers.」。三个关键点:
- 同构:Node / 浏览器 / Worker 一套代码,默认用
globalThis.fetch。 - 更易用:自动解析响应、自动序列化 body、非 2xx 抛错、内置重试与超时。
- fetch 底座:它是封装而非重写,行为与 fetch API 对齐,CORS/cookie 等仍由底层 fetch 决定。
二、安装与第一行代码
npm install ofetchimport { ofetch } from 'ofetch' // 具名导出
// const { ofetch } = require('ofetch') // CommonJS
const user = await ofetch('/api/user') // 直接拿到解析后的对象
console.log(user.name) // 无需 await res.json()对比原生 fetch:
await fetch(url).then(r => r.json())两步,ofetch 一步到位。要原始Response用ofetch.raw()(见下文)。
三、自动解析响应
ofetch 默认按响应的 content-type 智能选择解析方式:
const json = await ofetch('/api/data') // application/json → 对象
const html = await ofetch('/page.html') // text/* → 字符串
const img = await ofetch('/logo.png', { responseType: 'blob' }) // 强制 Blob可选 responseType:json(默认)、text、blob、arrayBuffer、stream。
解析很鲁棒
ofetch 默认解析器是 destr,比 JSON.parse 更稳:合法 JSON(含 42、true 这类标量)解析为对应值;非法 JSON 不抛错,原样返回字符串。
四、发请求带 body(自动序列化)
// POST 传普通对象 → 自动 JSON.stringify,并补 content-type / accept
await ofetch('/api/user', {
method: 'POST',
body: { name: 'foo', age: 18 },
})
// 其它方法同理
await ofetch('/api/user/1', { method: 'PATCH', body: { age: 19 } })
await ofetch('/api/user/1', { method: 'DELETE' })只有「可序列化对象」才自动 JSON 化
普通对象 / 数组会被自动 JSON.stringify。而 FormData、URLSearchParams、Blob、ReadableStream 不会被 JSON 化,会原样发送(流 body 还会自动设 duplex: 'half')。
五、查询参数 query
// 对象形式,底层用 ufo 拼接并编码
await ofetch('/api/list', { query: { page: 2, size: 10 } })
// → /api/list?page=2&size=10
// 与 URL 已有 query 合并(不是覆盖)
await ofetch('/api/list?b=2', { query: { a: 1 } })
// → /api/list?b=2&a=1
params是query的已废弃别名,仍可用但推荐query。
六、错误处理:非 2xx 自动抛错
原生 fetch 只在网络层失败才 reject,4xx/5xx 仍 resolve。ofetch 修正了这点——状态码非 2xx 时抛 FetchError:
import { ofetch, FetchError } from 'ofetch'
try {
await ofetch('/api/not-found')
} catch (err) {
console.log(err.message) // [GET] "/api/not-found": 404 Not Found
console.log(err.data) // 服务端返回的错误体(已解析)
console.log(err.status) // 404
console.log(err.statusText)// "Not Found"
}
// 也可内联拿错误体
const body = await ofetch('/api/maybe-fail').catch(e => e.data)从 axios 迁来的头号坑
axios 错误体在 error.response.data,ofetch 在 error.data。别找错地方。
七、复用配置:ofetch.create
给一组 API 统一加 baseURL、公共头、重试、拦截器,用 ofetch.create:
const api = ofetch.create({
baseURL: 'https://x.com/api',
headers: { 'X-App': 'demo' },
retry: 2,
timeout: 10000,
})
await api('/users') // 实际请求 https://x.com/api/users,自动套用所有默认值
await api('/users/1', { method: 'DELETE' })类似 axios 的
axios.create。它返回的实例本身还能再.create()派生子实例(见基础篇)。
掌握主线后,进入 指南 · 基础:拦截器四钩子、retry/timeout 默认值、ofetch.raw 与 _data、与 axios/ky 的取舍。