useFetch函数提供了中止请求、在请求发送前拦截请求、在url变化时自动重新获取请求等一系列很不错的api。
除了单一的使用useFetch之外,vueuse还提供了createFetch函数, 该函数返回一个useFetch函数,可以预先配置一些公用选项。这对于在整个项目中使用相同URL(即baseURL)或需要授权头的API进行交互以及API统一错误处理等是非常有用的。
关于useFetch及createFetch的使用示例及api参数请查看官方文档
以下是在具体项目中对createFetch的使用方式如下:
- 封装Fetch
// 1. fetch.ts
import { createFetch, CreateFetchOptions, UseFetchOptions } from '@vueuse/core';
import { objectToSearch } from '@/utils';
import type { IFeatchParams } from './types';
class Fetch {
instances;
constructor(params: CreateFetchOptions) {
const {
baseUrl,
combination = 'chain',
fetchOptions = {
mode: 'cors',
},
options,
} = params;
this.instances = createFetch({
baseUrl,
combination,
options,
fetchOptions,
});
}
get(
{ url, params = {} }: Omit<IFeatchParams, 'data'>,
featOptions: UseFetchOptions = {}
) {
return this.instances(
`${url}${objectToSearch(params) ? `?${objectToSearch(params)}` : ''}`,
featOptions
).json();
}
post(
{ url, data, params = {} }: IFeatchParams,
featOptions: UseFetchOptions = {}
) {
return this.instances(
`${url}${objectToSearch(params) ? `?${objectToSearch(params)}` : ''}`,
featOptions
)
.post(data)
.json();
}
put(
{ url, data, params = {} }: IFeatchParams,
featOptions: UseFetchOptions = {}
) {
return this.instances(
`${url}${objectToSearch(params) ? `?${objectToSearch(params)}` : ''}`,
featOptions
)
.put(data)
.json();
}
patch(
{ url, data, params = {} }: IFeatchParams,
featOptions: UseFetchOptions = {}
) {
return this.instances(
`${url}${objectToSearch(params) ? `?${objectToSearch(params)}` : ''}`,
featOptions
)
.patch(data)
.json();
}
delete(
{ url, params = {} }: IFeatchParams,
featOptions: UseFetchOptions = {}
) {
return this.instances(
`${url}${objectToSearch(params) ? `?${objectToSearch(params)}` : ''}`,
featOptions
)
.delete()
.json();
}
}
export default Fetch;
因为get请求的参数是直接拼接在url上(或许是我还没弄明白怎么像axios一样传参...),需要手动进行拼接,objectToSearch函数如下
// utils/objectToSearch.ts
export function objectToSearch(params: Record<string, any>) {
let searchParams = '';
if (Object.keys(params).length > 0) {
for (const key in params) {
searchParams += `${key}=${params[key]}&`;
}
searchParams = searchParams.slice(0, searchParams.length - 1);
}
return searchParams;
}
- 配置所有接口预设及请求头token、错误处理等
import { useLocalCache } from '@/hooks';
import Fetch from './fetch';
const { getCache, clearCache } = useLocalCache();
const whiteApis = ['/login']; // 接口白名单
export const Request = new Fetch({
baseUrl: import.meta.env.VITE_BASE_URL, // 这里的环境为vite,环境变量可自定义。当然也可以直接使用定值,例 '/api'
options: {
beforeFetch({ options, cancel, url }) {
const token = getCache('token');
if (!whiteApis.find((item) => url.includes(item)) && !token) {
cancel(); // 取消请求(不发送请求)
}
options.headers = {
...options.headers,
Authorization: token,
};
return { options };
},
afterFetch(ctx) {
// 这里做统一错误处理
const { code, message } = ctx.data;
if (code === 102) {
console.log('登录过期,请重新登录');
clearCache();
location.reload();
} else if (code !== 0) {
console.log(message || '请求失败,请稍后再试');
}
return ctx;
},
onFetchError(ctx) {
// 错误请求
console.log('错误的请求,请稍后再试');
return ctx;
},
timeout: 10000,
},
});
上面引入的useLocalCache见 1.vueuse-useLocalStorage在项目中的使用
- 使用示例
import { Request } from '@/service';
interface ILogin {
password: string;
username: string;
}
export function Login(data: ILogin) {
return Request.post({
url: 'login',
data,
});
}
// 1. 使用(中止请求)
const { abort, data } = Login({ password: 'admin123', username: 'sy' })
abort() // 中止请求,同 execute
console.log(data.value) // undefined
// 2. 使用
Login({ password: 'admin123', username: 'sy' }).then((res) => {
const { code, data } = res.data.value;
if (code === 0) {
console.log('data', data);
}
});
- 优化请求
export function useHandleApiRes<T = any>(promise: PromiseLike<any>) {
return promise.then((res) => {
const { data } = res;
const { code, message, data: resData } = unref(data) || {};
return {
code,
message,
data: resData as T,
};
});
}
// 示例
interface ILoginRes {
username: string;
avatar: string;
}
const submit = async () => {
const { code, data, message } = await useHandleApiRes<ILoginRes>(
Login({ password: 'admin1234', username: 'sy' })
);
if (code === 0) {
console.log('data', data);
} else {
console.log(message);
};
useFetch/createFetch的使用及封装,相对axios来说更灵活简单些,配置起来也不会太麻烦。且项目中用到vueuse之后可以少安装很多npm包了。用起来还是很香的~