【Nuxt系列文章】一文读懂Nuxt3的网络请求
大家好,我是刘明,十年创业老兵,开源技术爱好者。
有童鞋问我,Nuxt3如何整合Axios?我的答案是,不要在Nuxt3里整合Axios.
虽说Axios很好用,并且多数同学都已经很熟悉Axios的使用。但是Nuxt3官方团队已经不建议使用Axios。本文将向各位童鞋介绍:
- 为何官方不推荐Axios
- 如何在Nuxt3中封装类似Axios一样的功能。
Axios的前世今生
Axios的诞生
在早期,浏览器中发起网络请求需要用到XMLHttpRequest 对象,在node后端环境中发起网络请求需要用到http模块。两者写法不一样,用起来也比较复杂。于是Axios对两者做个一个封装,统一了前后端的写法。
对于开发者而言,只要用上了Axios,就不需要再区分是node还是浏览器环境,反正二者写法上都是一样的。不仅如此,Axios还有请求拦截和响应拦截等高级功能。所以,Axios很快就流行起来。Nuxt2也有整合好的Axios模块,并且官方也曾大力推荐。
Axios的落伍
到了Nuxt3,时代变了。
首先是浏览器环境。浏览器原生支持fetch,并且有代替XMLHttpRequest的趋势。
紧接着是Node.2022年2月,Node v17.5发布,引入了对fetch的原生支持。
至此,fetch在前后端大统一了。
回头再看,Axios前端封装XMLHttpRequest后端封装http的做法就完全没有必要了。
如何看待Axios
虽然fetch在前后端大统一,但是还有很多童鞋喜欢使用Axios.这是正常的,毕竟Axios确实很好用,而且很多老项目仍然需要维护。
以至于,我在网上看到一些文章,拿Axios和Fetch进行对比的时候,得出的结论是Axios比fetch好。其实这是一个非常错误的对比。Axios是一个封装好的项目,fetch只是一个原生API.如果非要对比的话,应该拿XMLHttpRequest对象和fetch比或者http模块与fetch比。
随着时间推移,越来越多的新项目会推荐使用fetch.Nuxt3是2022年诞生的新项目,完全放弃使用Axios。
Nuxt3的官方做法
拿Axios和Fetch进行对比并得出结论说Axios更好用,虽然是一个错误的对比。但至少说明一点,fetch要想真正获得认可,应该有一个非常好用的封装。Nuxt3的官方团队考虑到了这一点,将fetch进一步封装,开发了一个新项目叫做ofetch,并且将ofetch集成到Nuxt3中。Nuxt3中有个随处可用的全局对象$fetch,就是ofetch.
我看过ofetch的全部代码,与Axios相比代码量少,Axios有的功能ofetch也基本都有。官方在Nuxt3中默认集成了ofetch,ofetch已经是Nuxt3项目不可缺少的一部分。所以他们自然不再推荐Axios.
如何在Nuxt3中封装出类似Axios一样的功能
在Nuxt3官方文档DataFeching部分,介绍了useFech和$fetch的简单用法,如果是刚刚上手Nuxt3的童鞋,强烈建议仔细阅读此部分。
但是很多项目还需要设置baseURL,还需要请求拦截和相应拦截。这些功能在官方文档中都没有给出代码案例。
实现起来很简单,只需要再写一个useRequest的组合函数即可。在Nuxt3中,组合函数是自动导入的,所以写出来就可以用了。
//文件位置:/composables/useRequest.ts
type Response = {
url: string;
body:any,
status: number;
type:string,
statusText?: string;
_data?: any;
headers?:object,
ok?:boolean,
redirected?:boolean,
bodyUsed?:boolean,
};
type ResponseData={
code:number,
msg:string,
data:object|object[]
}
export const useRequest = async (url: string,options:object) => {
const router = useRouter();
//此处是引入了pinia进行状态管理,大家可以根据自己需求进行重写
//const store = useMainStore();
const host = window.location.hostname;
const headers = {
Authorization:'Bearer '+localStorage.getItem('token')||null,
};
const defaultOptions:object = {
//baseURL也可以在nuxt.config.ts中定义然后此处引入
baseURL: "http://example.com",
headers: headers,
//响应拦截
onResponse({ response }: { response: Response }) {
console.log("response", response);
const res = response._data;
//后端返回code=0时弹出错误信息,此处采用了element-plus
if (res.code == 0) {
ElMessage.error(res.msg);
}
},
//响应错误拦截
onResponseError({ response }: { response: Response }) {
console.log("response-error", response);
const res = response._data;
//后端返回401时导航到登录界面
if (response.status == 401) {
router.replace("/login");
//store.logout()
}
},
};
const newOptions:object={...defaultOptions,...options};
//采用element-plus进行请求时的加载
//const loadingInstance = ElLoading.service({fullscreen:false});
const { data, pending,refresh } = await useFetch(url, newOptions);
if (!pending.value) {
//loadingInstance.close();
}
return {data,refresh};
};
以上封装代码采用的是TypeScript写法,如果不习惯TypeScript,可以私信我获取javascript写法。
这个封装中,主要实现了以下几个功能:
- 添加了全局的baseURL,
- 在请求中添加了全局的header,header中包含token,用于后端的身份认证
- 添加了响应拦截,对于错误信息进行了统一提示,并对401错误自动转入登录界面
- 网络请求时增加了elemeng-plus的laoding组件,自动处理loading的打开和关闭
这个封装其实就是对于官方useFetch的进一步加工,封装后,返回的仍然是useFetch的data和refresh.使用方法和useFetch基本一致。
如果你对useFetch的使用还不熟悉,直接查看官方文档。
文档链接:useFetch使用文档
以上代码,只是给一个example,童鞋们完全可以根据自己的需求进行重写。比如,再写一个useGet或者usePost组合函数,以免每次请求都需要选择method.或者,再增加一些复杂的请求拦截.
重点是,一定要弄懂ofetch的用法。只有这样,才能根据自己的需求,随意改造代码。
我是刘明,十年创业老兵,开源技术爱好者。无论你是交流学习,还是有开发需求,欢迎私信联系。
有问题,找老刘
- 点赞
- 收藏
- 关注作者
评论(0)