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>
结果:

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

相关推荐
z千鑫13 分钟前
【前端】详解前端三大主流框架:React、Vue与Angular的比较与选择
前端·vue.js·react.js
m0_748256141 小时前
前端 MYTED单篇TED词汇学习功能优化
前端·学习
小马哥编程2 小时前
Function.prototype和Object.prototype 的区别
javascript
小白学前端6662 小时前
React Router 深入指南:从入门到进阶
前端·react.js·react
苹果醋32 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计
web130933203982 小时前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
王小王和他的小伙伴2 小时前
解决 vue3 中 echarts图表在el-dialog中显示问题
javascript·vue.js·echarts
学前端的小朱2 小时前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
outstanding木槿2 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08213 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架