Nuxt3数据请求及封装


前言

这篇文章记录一下Nuxt3网络请求的方法,结合了自己项目的需求对其中的数据请求进行了统一的封装,这样可以统一处理公共的请求逻辑,采用的是Nuxt3自带的useFetch方法。


一、Nuxt3中数据请求方式

Nuxt3提供了多种方法来处理应用程序中的数据获取:

  • $fetch
  • useFetch
  • useLazyFetch
  • useAsyncData
  • useLazyAsyncData

二、unjs/ofetch库

Nuxt3 不推荐也没必要使用Axios进行网络请求,Axios本来是对 XMLHttpRequest 的封装,而现如今网络请求这种功能由 XMLHttpRequest 逐渐被 Fetch API 代替,浏览器已支持原生支持fetch,Node v17.5也引入了对fetch的原生支持。Nuxt3的官方团队将fetch进一步封装,封装的项目叫做ofetch,并且将其集成到Nuxt3中,就是开头提到的$fetch方法。

三、请求方式之间的区别

1. useAsyncData

需要提供一个用于缓存去重的 key 和数据请求的处理函数。
第一个参数是 key,但是即使你不传 key,Nuxt 也会根据文件名和行号帮你生成一个。

const { data, pending, error, refresh } = await useAsyncData(
  'mountains',
  () => $fetch('https://api.nuxtjs.dev/mountains')
)

2. useFetch

useFetch这个可组合函数提供了一个方便的包装器,用于useAsyncData和$fetch。它会自动生成基于URL和fetch选项的键,根据服务器路由提供请求URL的类型提示,并推断API响应类型。
对useFetch的多个调用,建议使用<script setup>,因为它消除了使用顶级等待的限制。

useFetch 是对 useAsyncData 的一层包装,可以理解为所有的都选择默认配置的useAsyncData 方法,useFetch(url)几乎等同于useAsyncData(url, () => $fetch(url))——它是最常见用例的开发人员语法糖。

const param1 = ref('value1')
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
    query: { param1, param2: 'value2' }
})

3. useLazyAsyncData 与 useLazyFetch

这两个Api分别对应useAsyncData和useFetch,用法一致,只是把配置选项中的 Lazy 设置成了true,即使用useLazyFetch 和 useLazyAsyncData 在客户端渲染时不会阻塞导航的跳转,这意味着你需要处理数据为null的情况,给 data 设置一个默认值;而在服务端渲染效果是一样的,还是会阻塞页面渲染。

四、封装useFetch

由于useFetch已经是经过封装简化后的请求方式,所以基于useFetch方法进行进一步的封装,主要是添加全局的baseURL,还有添加了请求与响应拦截。这里按照实际项目需求来封装就好。

封装前有几点 Nuxt3 的使用技巧介绍一下:

1. Nuxt3使用技巧

①:Composables 目录自动导入

Nuxt 3使用composables/目录使用auto-imports自动将Vue组合导入到应用中!

默认情况下Nuxt3会自动导入此目录下的第一级文件,所以将封装网络请求的函数写在此目录下并导出即可在项目内自由使用。

②:定义 Runtime Config 公共变量

useRuntimeConfig 用于在应用程序中公开配置变量。

定义在客户端使用的公共变量:

export default defineNuxtConfig({
  runtimeConfig: {
    // apiSecret 只能在服务器端上访问
    apiSecret: '123',
    // public 命名空间中定义的,在服务器端和客户端都可以普遍访问
    public: {
      apiBase: process.env.NUXT_PUBLIC_API_BASE
    }
  }
})

使用方式:

  const config = useRuntimeConfig();
  const baseURL = config.public.apiBase;

③:定义env环境变量

在 production runtime时, 你应该使用平台环境变量,.env没有被使用 。

在客户端直接使用 process.env 访问环境变量是拿不到.env里的内容的,在服务端node环境才可以,所以一定得配合useRuntimeConfig来使用.env里的配置。

可以使用前缀为NUXT_的匹配环境变量名来更新运行时配置值。

//.env.development
NUXT_PUBLIC_API_BASE = 'https://api-test.com'
//.env.production
NUXT_PUBLIC_API_BASE = 'https://api.com'

下面正式进入封装数据请求函数环节。

2. 封装函数

// composables/getData.ts
import type { NitroFetchRequest } from 'nitropack';
import type { FetchOptions } from 'ofetch';
// import { showToast, showLoadingToast, closeToast } from 'vant';

interface Params {
  url: NitroFetchRequest;
  opts: FetchOptions<any>;
  method?: 'get' | 'post';
  contentType: 'application/x-www-form-urlencoded' | 'application/json';
}

let loadingCount = 0;

// 转换动态接口,兼容类似'/article/:id'这样的动态接口
const replacePathVariables = (url: NitroFetchRequest, params: any = {}) => {
  if (Object.keys(params).length === 0) {
    return url;
  }
  const regex = /\/:(\w+)/gm;
  let formattedURL = url as string;
  let m = regex.exec(formattedURL);
  while (m) {
    if (m.index === regex.lastIndex) {
      regex.lastIndex += 1;
    }
    if (params[m[1]] === undefined) {
      throw new Error(`"${m[1]}" is not provided in params`);
    }
    formattedURL = formattedURL.replace(`:${m[1]}`, params[m[1]]);
    delete params[m[1]];
    m = regex.exec(formattedURL);
  }
  return formattedURL;
};

export async function getFetchData({
  url,
  opts,
  method = 'get',
  contentType = 'application/json',
}: Params) {
  const config = useRuntimeConfig();
  const requestURL = replacePathVariables(url, opts);
  const { data } = await useFetch(requestURL, {
    method,
    // ofetch库会自动识别请求地址,对于url已包含域名的请求不会再拼接baseURL
    baseURL: config.public.baseURL,
    // onRequest相当于请求拦截
    onRequest({ request, options }) {
      // 设置请求头
      options.headers = { 'Content-Type': contentType };
      // 设置请求参数
      if (method === 'post') {
        options.body = { ...opts };
      } else {
        options.query = { ...opts };
      }
      if (loadingCount === 0) {
        // showLoadingToast({ forbidClick: true });
      }
      loadingCount++;
    },
    // onResponse相当于响应拦截
    onResponse({ response }) {
      // 处理响应数据
      loadingCount--;
      if (loadingCount === 0) {
        // closeToast();
      }
      if (response._data.error) {
        console.warn(
          '=== error url: ',
          url,
          '\n params:',
          opts,
          '\n response:',
          response._data
        );
        // showToast(response._data.message);
      } else {
        return response;
      }
    },
    onRequestError({ request, options, error }) {
      // 处理请求错误
      // console.warn('request error', error);
      // showToast('Request Error');
    },
    onResponseError({ request, response, options }) {
      // 处理响应错误
      // console.warn('request error', response);
      // showToast('Request Error');
    },
  });
  // 这里data本身是个ref对象,将其内部值抛出去方便调用时获得数据。
  return data.value;
}

3. 调用

项目内直接使用getFetchData方法处理异步请求

<script setup>
// get请求
const res = await getFetchData({
  url: 'xxx/getList',
  opts: { id: 1 },
});

// post请求
const res = await getFetchData({
  url: '/xxx/getList',
  opts: {
    memberLevel: 1,
    pageNum: 1,
    pageSize: 10,
  },
  method: 'post',
});
</script>

总结

以上就是全部内容,本文简单介绍了Nuxt3的数据获取方式,详细使用方式与使用技巧还需多参考官方文档以及社区优秀项目。关于封装数据请求这块,之前也有写过Axios封装相关的博客,感兴趣的同学可以参考(axios封装—vue3项目),此次对Nuxt3的封装也只是基本展示,需要结合自身业务需求灵活使用。另外本人也是刚学习Nuxt3不久,若有不当之处,敬请指正。
如果此篇文章对您有帮助,欢迎您【点赞】、【收藏】!也欢迎您【评论】留下宝贵意见,共同探讨一起学习~

评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值