Nuxt 3 中的 $fetch
方法详解
$fetch
是 Nuxt 3 提供的一个内置 HTTP 客户端方法,用于在客户端和服务器端发起 HTTP 请求。它是基于 ohmyfetch 库构建的,提供了简洁的 API 和强大的功能。
基本用法
在组件中使用
<script setup>
const { data } = await useFetch('/api/hello')
// 或者直接使用 $fetch
const response = await $fetch('/api/hello')
</script>
在 API 路由中使用
// server/api/hello.ts
export default defineEventHandler(async (event) => {
const data = await $fetch('https://api.example.com/data')
return { data }
})
主要特性
- 自动处理 baseURL:在客户端会自动添加应用的 baseURL
- 自动解析 JSON:响应会自动解析为 JavaScript 对象
- 同构请求:在服务器端和客户端使用相同的 API
- TypeScript 支持:内置类型推断
请求选项
$fetch
接受第二个参数作为配置选项:
const data = await $fetch('/api/posts', {
method: 'POST',
body: { title: 'New Post' },
headers: {
'Authorization': 'Bearer token'
},
params: {
page: 1
},
// 其他选项...
})
常用选项
• method
: HTTP 方法 (GET, POST, PUT, DELETE 等) • body
: 请求体 (自动转换为 JSON) • headers
: 请求头 • params
: 查询参数 (会自动编码) • baseURL
: 基础 URL • timeout
: 超时时间 (毫秒) • retry
: 重试次数 • onRequest
: 请求拦截器 • onResponse
: 响应拦截器 • onRequestError
: 请求错误处理 • onResponseError
: 响应错误处理
错误处理
try {
const data = await $fetch('/api/posts')
} catch (error) {
console.error('请求失败:', error.statusCode, error.message)
}
与 useFetch
的区别
$fetch
是底层 API,而useFetch
是组合式函数useFetch
提供了响应式数据和更多 Vue 集成功能useFetch
会自动缓存请求结果
高级用法
拦截器
const api = $fetch.create({
baseURL: '/api',
onRequest({ request, options }) {
// 添加认证头
options.headers = options.headers || {}
options.headers.Authorization = 'Bearer token'
},
onResponseError({ response }) {
// 处理错误响应
console.error('响应错误:', response.status, response._data)
}
})
自定义解析器
const csvData = await $fetch('/data.csv', {
parseResponse: txt => parseCSV(txt)
})
取消请求
const controller = new AbortController()
$fetch('/api/data', {
signal: controller.signal
})
// 取消请求
controller.abort()
注意事项
- 在服务器端使用时,
$fetch
会自动继承当前请求的 cookie 和 headers - 对于跨域请求,需要正确配置服务器 CORS
- 在生产环境中,建议为 API 请求添加适当的错误处理和重试机制
$fetch
是 Nuxt 3 中处理 HTTP 请求的推荐方式,它简化了网络请求的复杂性,同时提供了强大的功能和灵活性。
封装成独立库
Nuxt 3 HTTP 请求库封装
下面是一个独立的 HTTP 请求库封装,支持 GET、POST、DELETE、PUT 方法,兼容服务端和客户端,并自动携带认证令牌。
实现代码
创建 utils/http.js
文件:
// utils/http.js
export const useHttp = () => {
const config = useRuntimeConfig()
const auth = useAuth() // 假设有一个 useAuth 组合式函数提供 token
// 创建基础实例
const http = $fetch.create({
baseURL: config.public.apiBaseUrl || '/api',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
// 请求拦截器 - 自动添加 token
const onRequest = async ({ options }) => {
const token = auth.value?.token
if (token) {
options.headers = options.headers || {}
options.headers.Authorization = `Bearer ${token}`
}
}
// 响应拦截器 - 统一错误处理
const onResponseError = async ({ response }) => {
if (process.client) {
// 客户端特定错误处理,例如显示通知
console.error('请求错误:', response.status, response._data)
if (response.status === 401) {
// 处理 token 过期等情况
await auth.value.logout()
navigateTo('/login')
}
}
// 继续抛出错误以便调用方处理
throw response._data
}
// 封装各种请求方法
const get = (url, params = {}, options = {}) => {
return http(url, {
method: 'GET',
params,
...options,
onRequest,
onResponseError
})
}
const post = (url, body = {}, options = {}) => {
return http(url, {
method: 'POST',
body,
...options,
onRequest,
onResponseError
})
}
const put = (url, body = {}, options = {}) => {
return http(url, {
method: 'PUT',
body,
...options,
onRequest,
onResponseError
})
}
const del = (url, params = {}, options = {}) => {
return http(url, {
method: 'DELETE',
params,
...options,
onRequest,
onResponseError
})
}
return {
get,
post,
put,
delete: del, // delete 是保留字,所以用 del
$fetch: http // 原始 $fetch 实例
}
}
使用示例
1. 在组件中使用
<script setup>
const { get, post, put, delete: del } = useHttp()
// GET 请求
const fetchData = async () => {
try {
const data = await get('/posts', { page: 1 })
console.log(data)
} catch (error) {
console.error('获取数据失败:', error)
}
}
// POST 请求
const createPost = async () => {
try {
const result = await post('/posts', { title: '新文章', content: '内容' })
console.log('创建成功:', result)
} catch (error) {
console.error('创建失败:', error)
}
}
</script>
2. 在 API 路由中使用
// server/api/posts/index.ts
export default defineEventHandler(async (event) => {
const { get } = useHttp()
const externalData = await get('https://api.example.com/posts')
return externalData
})
配套的 auth 存储实现
创建 composables/useAuth.ts
:
// composables/useAuth.ts
export const useAuth = () => {
const auth = useState('auth', () => ({
token: null,
user: null
}))
const setAuth = (token, user) => {
auth.value.token = token
auth.value.user = user
// 客户端存储 token
if (process.client) {
localStorage.setItem('token', token)
}
}
const logout = () => {
auth.value.token = null
auth.value.user = null
if (process.client) {
localStorage.removeItem('token')
}
}
// 初始化时从 localStorage 恢复 token
if (process.client) {
const token = localStorage.getItem('token')
if (token) {
auth.value.token = token
}
}
return {
auth,
setAuth,
logout
}
}
配置
在 nuxt.config.ts
中添加:
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBaseUrl: process.env.API_BASE_URL || 'https://api.example.com'
}
}
})
特性说明
- 同构请求:在服务端和客户端都能使用相同的 API
- 自动携带令牌:请求时自动添加 Authorization 头
- 统一错误处理:集中处理 401 等错误状态
- 类型安全:配合 TypeScript 使用更安全
- 灵活的配置:可以自定义 baseURL、headers 等
- 拦截器支持:请求和响应拦截器
扩展建议
- 可以添加请求/响应转换器
- 实现请求缓存功能
- 添加请求取消支持
- 实现文件上传的特殊处理
- 添加更详细的日志记录
这个封装提供了良好的基础结构,你可以根据项目需求进一步扩展和完善。
以上为AI生成的
我的封装
以下是我封装的
import {useCookie} from "nuxt/app";
const baseReq = (url, options = {}) => {
const token = useCookie('sob-ut').value;
return new Promise((resolve, reject) => {
$fetch(url, {
headers: {
'sob-ut': token
},
...options,
onResponse: ({response}) => {
const nToken = response.headers.get('sob-ut');
if (nToken) {
//todo:更新到其他域名
}
}
}).then(res => {
resolve(res);
}).catch(error => {
reject(error);
});
})
}
export const fetchGet = (url) => {
return baseReq(url, {method: 'GET'})
}
export const fetchPost = (url, body) => {
return baseReq(url, {
method: 'POST',
contentType: 'application/json',
body: body
})
}
export const fetchPostFile = (url, file) => {
return baseReq(url,{
method:'POST',
contentType:'application/x-www=form-urlencoded',
body: file
})
}
我的目的是啥呢?请求的时候,自动携带令牌,响应的时候拦截令牌,如果有更新,同步更新到其他的域名,这样子就可以一个号登录,各个平台使用了。