Nuxt3封装网络请求 useFetch & $fetch

前言:

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

文档:

数据获取 · 快速入门 Nuxt

关键:

  • useFetch 是在组件设置函数中处理数据获取的最简单方法。
  • [fetch](https://nuxt.com.cn/docs/api/utils/dollarfetch "fetch") 可以根据用户交互进行网络请求。
  • useAsyncData 结合 $fetch,提供了更精细的控制。

讲解:

useAsyncData:
  • 提供了一种在SSR友好的组合式中访问异步解析数据的方式
  • 注意,setup期间,这里结合了$fetch,并且设置了一个key,一个唯一的键,用于确保数据获取可以在请求中正确去重
javascript 复制代码
<script setup>
const { data, pending, error, refresh } = await useAsyncData(
  'mountains',
  () => $fetch('https://api.nuxtjs.dev/mountains')
)
</script>
  • 当 CMS 或第三方提供自己的查询层时。在这种情况下,您可以使用 useAsyncData 来封装您的调用,并仍然保持组合函数提供的好处。
$fetch:
javascript 复制代码
<script setup lang="ts">
// 在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>
javascript 复制代码
<script setup lang="ts">
function contactForm() {
  $fetch('/api/contact', {
    method: 'POST',
    body: { hello: 'world '}
  })
}
</script>

<template>
  <button @click="contactForm">联系我们</button>
</template>
useFetch :
  • 使用一个与SSR兼容的可组合函数从API端点获取数据。
  • 包装了useAsyncData和[fetch](https://nuxt.com.cn/docs/api/utils/dollarfetch "fetch"),它返回响应式的可组合函数,并处理将响应添加到Nuxt的负载中,以便在页面水合时可以从服务器传递给客户端,而无需在客户端重新获取数据。
  • (水合的概念在文档的渲染模式有讲解:渲染模式 · 关键概念 (nuxt.com.cn)
  • 提供了拦截器
javascript 复制代码
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()解构,示例:
javascript 复制代码
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      API_BASE_DEV: 'http://localhost:4000',
      API_BASE_PROD: 'https://api.example.com/v1'
    }
  },
})
  • 当然你还可以
composables:
封装$fetch
    • composables/useDollarFetchRequest.ts
TypeScript 复制代码
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
TypeScript 复制代码
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 示例:
javascript 复制代码
import { useDollarGet } from '~/composables/useDollarFetchRequest';

export const getDocsApi = () => useDollarGet('/docs/list');
javascript 复制代码
<template>
    <div>
      <button @click="handleGetUserInfo">获取用户信息</button>
    </div>

    <HomeCover />
    <HomeIntro />
    <HomeCadre />
    <HomeJoinUs />
    <BackToTop />
</template>

<script setup lang="ts">
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 示例
TypeScript 复制代码
<script setup lang="ts">
import { getDocsApi } from '../../api/home/joinUs';

try {
  const response = await getDocsApi();
  console.log('文档列表:', response.data.value);
} catch (error) {
  console.error('获取文档列表出错:', error);
}

</script>
结果:

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

相关推荐
passerby606125 分钟前
完成前端时间处理的另一块版图
前端·github·web components
掘了32 分钟前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅35 分钟前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment1 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端
爱敲代码的小鱼2 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
吹牛不交税2 小时前
admin.net-v2 框架使用笔记-netcore8.0/10.0版
vue.js·.netcore