前言:
刚接触、搭建Nuxt3项目的过程还是有点懵的,有种摸石头过河的感觉,对于网络请求这块,与之前的Vue3项目有所区别,在Vue项目通常使用axios这个库进行网络请求,但在Nuxt项目并不推荐,因为有内置 fetch 相关...接下来一起学习一下Nuxt3数据请求的点点滴滴吧~
文档:
数据获取 · 快速入门 Nuxt
关键:
useFetch 是在组件设置函数中处理数据获取的最简单方法。
$fetch 可以根据用户交互进行网络请求。
useAsyncData 结合 $fetch,提供了更精细的控制。
讲解:
useAsyncData:
Nuxt使用 ofetch 来全局暴露`$fetch`辅助函数,用于在Vue应用程序或API路由中进行HTTP请求
源码:nuxt/packages/nuxt/src/app/entry.ts at main · nuxt/nuxt · GitHub
$fetch是在Nuxt中进行HTTP调用的首选方式,而不是为Nuxt 2设计的@nuxt/http和@nuxtjs/axios。
比如,你的页面有给用户提供交互的(按钮),那么就可以使用 $fetch ,不然控制台会有警告,网上就有不少人是在交互的时候使用useFetch而出现问题,看下面这篇文章
警告:[nuxt] [useFetch] Component is already mounted, please use $fetch instead. See https://nuxt.com/docs/getting-started/data-fetching
Nuxt 3:正确的方法 --- useFetch in Nuxt 3: The Proper Way (alex.party)
请观察以下调用接口的时机:setup | click
$fetch('/api/item')) // 你也可以使用useFetch作为useAsyncData + $fetch的快捷方式 const { data } = await useFetch('/api/item')" _ue_custom_node_="true">
联系我们
useFetch :
在nuxt.config.ts配置 runtimeConfig,通过useRuntimeConfig()解构,示例:
export default defineNuxtConfig({ runtimeConfig: { public: { API_BASE_DEV: 'http://localhost:4000', API_BASE_PROD: 'https://api.example.com/v1' } }, })
封装$fetch
- composables/useDollarFetchRequest.ts
import { $fetch } from 'ofetch'; import { useRuntimeConfig } from '#app'; interface RequestOptions { customBaseURL?: string; [key: string]: any; } type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; // 请求拦截器 function handleRequest(options: RequestOptions) { options.headers = { ...options.headers, 'Content-Type': 'application/json', }; } // 响应拦截器 function handleResponse(response: any) { if (response.error) { throw new Error(response.error.message || '响应错误'); } return response; } /** * 创建请求方法 * @param method */ function createDollarFetchRequest(method: HttpMethod) { return async function ( url: string, data?: any, options: RequestOptions = {} ) { const { public: { API_BASE_DEV, API_BASE_PROD } } = useRuntimeConfig(); const baseURL = process.env.NODE_ENV === 'production' ? API_BASE_PROD : API_BASE_DEV; const requestUrl = new URL( url, options.customBaseURL || baseURL ).toString(); try { handleRequest(options); const response = await $fetch(requestUrl, { method, body: data, ...options, }); return handleResponse(response); } catch (error) { console.error('请求错误:', error); throw error; } }; } // 提供 $fetch & HTTP 方法 - 统一管理请求 - 再到组件中使用 export const useDollarGet = createDollarFetchRequest('GET'); export const useDollarPost = createDollarFetchRequest('POST'); export const useDollarPut = createDollarFetchRequest('PUT'); export const useDollarDelete = createDollarFetchRequest('DELETE');
调用 $fetch 示例:
import { useDollarGet } from '~/composables/useDollarFetchRequest'; export const getDocsApi = () => useDollarGet('/docs/list');
获取用户信息 { try { const data = await getDocsApi(); console.log('文档列表:', data); } catch (error) { console.error('获取文档列表出错:', error); } };" _ue_custom_node_="true">
调用 useFetch 示例
结果:
欢迎三连,以及在评论区讨论,如果有不对的还请告知纠正
封装useFetch
- composables/useFetchRequest.ts
import { useFetch, useRuntimeConfig } from '#app'; import type { UseFetchOptions } from 'nuxt/app'; interface RequestOptions extends UseFetchOptions { customBaseURL?: string; } type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; type HandleRequestOptions = { request: Request; options: RequestOptions }; type HandleResponseOptions = { response: any }; // 请求拦截器 function handleRequest({ options }: HandleRequestOptions) { options.headers = { ...options.headers, 'Content-Type': 'application/json', }; } // 响应拦截器 function handleResponse({ response }: HandleResponseOptions) { if (response._data.error) { throw new Error(response._data.error.message || '响应错误'); } return response._data; } /** * 创建请求方法 * @param method */ function createUseFetchRequest(method: HttpMethod) { return async function ( url: string, data?: any, options: RequestOptions = {} ) { const { public: { API_BASE_DEV, API_BASE_PROD } } = useRuntimeConfig(); const baseURL = process.env.NODE_ENV === 'production' ? API_BASE_PROD : API_BASE_DEV; const requestUrl = new URL( url, options.customBaseURL || baseURL ).toString(); return await useFetch(requestUrl, { ...options, method, body: data, onRequest: handleRequest, onResponse: handleResponse }); }; } // 提供 useFetch & HTTP 方法 - 统一管理请求 - 再到组件中使用 export const useFetchGet = createUseFetchRequest('GET'); export const useFetchPost = createUseFetchRequest('POST'); export const useFetchPut = createUseFetchRequest('PUT'); export const useFetchDelete = createUseFetchRequest('DELETE');
统一管理 API
当然你还可以
composables:
使用一个与SSR兼容的可组合函数从API端点获取数据。
包装了useAsyncData和$fetch,它返回响应式的可组合函数,并处理将响应添加到Nuxt的负载中,以便在页面水合时可以从服务器传递给客户端,而无需在客户端重新获取数据。
(水合的概念在文档的渲染模式有讲解:渲染模式 · 关键概念 (nuxt.com.cn))
提供了拦截器
const { data, pending, error, refresh } = await useFetch('/api/auth/login', { onRequest({ request, options }) { // 设置请求头 options.headers = options.headers || {} options.headers.authorization = '...' }, onRequestError({ request, options, error }) { // 处理请求错误 }, onResponse({ request, response, options }) { // 处理响应数据 localStorage.setItem('token', response._data.token) }, onResponseError({ request, response, options }) { // 处理响应错误 } })
事实上,useFetch(url) 几乎等同于 useAsyncData(url, () => $fetch(url)) - 它是为最常见的用例提供的开发者体验糖。
封装:工厂函数设计请求代码结构
env:
提供了一种在SSR友好的组合式中访问异步解析数据的方式
注意,setup期间,这里结合了$fetch,并且设置了一个key,一个唯一的键,用于确保数据获取可以在请求中正确去重
$fetch('https://api.nuxtjs.dev/mountains') )" _ue_custom_node_="true">
当 CMS 或第三方提供自己的查询层时。在这种情况下,您可以使用 useAsyncData 来封装您的调用,并仍然保持组合函数提供的好处。
$fetch: