Nuxt3封装网络请求 useFetch & $fetch

临枫541 2024-08-18 14:03:01 阅读 96

前言:

刚接触、搭建Nuxt3项目的过程还是有点懵的,有种摸石头过河的感觉,对于网络请求这块,与之前的Vue3项目有所区别,在Vue项目通常使用axios这个库进行网络请求,但在Nuxt项目并不推荐,因为有内置 fetch 相关...接下来一起学习一下Nuxt3数据请求的点点滴滴吧~

文档:

数据获取 · 快速入门 Nuxt

关键:

useFetch 是在组件设置函数中处理数据获取的最简单方法。$fetch 可以根据用户交互进行网络请求。useAsyncData 结合 <code>$fetch,提供了更精细的控制。

讲解:

useAsyncData:

提供了一种在SSR友好的组合式中访问异步解析数据的方式注意,setup期间,这里结合了$fetch,并且设置了一个key,一个唯一的键,用于确保数据获取可以在请求中正确去重

<script setup>

const { data, pending, error, refresh } = await useAsyncData(

'mountains',

() => $fetch('https://api.nuxtjs.dev/mountains')

)

</script> 当 CMS 或第三方提供自己的查询层时。在这种情况下,您可以使用 useAsyncData 来封装您的调用,并仍然保持组合函数提供的好处。 

$fetch:

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-fetchingNuxt 3:正确的方法 --- useFetch in Nuxt 3: The Proper Way (alex.party)请观察以下调用接口的时机:setup | click

<script setup lang="ts">code>

// 在SSR中数据将被获取两次,一次在服务器端,一次在客户端。

const dataTwice = await $fetch('/api/item')

// 在SSR中,数据仅在服务器端获取并传递到客户端。

const { data } = await useAsyncData('item', () => $fetch('/api/item'))

// 你也可以使用useFetch作为useAsyncData + $fetch的快捷方式

const { data } = await useFetch('/api/item')

</script>

<script setup lang="ts">code>

function contactForm() {

$fetch('/api/contact', {

method: 'POST',

body: { hello: 'world '}

})

}

</script>

<template>

<button @click="contactForm">联系我们</button>code>

</template>

useFetch :

使用一个与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:

在nuxt.config.ts配置 runtimeConfig,通过useRuntimeConfig()解构,示例:

export default defineNuxtConfig({

runtimeConfig: {

public: {

API_BASE_DEV: 'http://localhost:4000',

API_BASE_PROD: 'https://api.example.com/v1'

}

},

})

当然你还可以

 composables:

封装$fetch
- composables/useDollarFetchRequest.ts

<code>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');

封装useFetch
- composables/useFetchRequest.ts

import { useFetch, useRuntimeConfig } from '#app';

import type { UseFetchOptions } from 'nuxt/app';

interface RequestOptions extends UseFetchOptions<any> {

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 

调用 $fetch 示例:

import { useDollarGet } from '~/composables/useDollarFetchRequest';

export const getDocsApi = () => useDollarGet('/docs/list');

<template>

<div>

<button @click="handleGetUserInfo">获取用户信息</button>code>

</div>

<HomeCover />

<HomeIntro />

<HomeCadre />

<HomeJoinUs />

<BackToTop />

</template>

<script setup lang="ts">code>

import HomeCover from './HomeCover.vue';

import HomeIntro from './HomeIntro.vue';

import HomeCadre from './HomeCadre.vue';

import HomeJoinUs from './HomeJoinUs.vue';

import { getDocsApi } from '../../api/home/joinUs';

const handleGetUserInfo = async () => {

try {

const data = await getDocsApi();

console.log('文档列表:', data);

} catch (error) {

console.error('获取文档列表出错:', error);

}

};

</script>

调用 useFetch 示例

<script setup lang="ts">code>

import { getDocsApi } from '../../api/home/joinUs';

try {

const response = await getDocsApi();

console.log('文档列表:', response.data.value);

} catch (error) {

console.error('获取文档列表出错:', error);

}

</script>

结果:

 


 欢迎三连,以及在评论区讨论,如果有不对的还请告知纠正 



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。