前言
上一篇我们完成了前期准备和路由的封装:React+ts+vite脚手架搭建(一)【前期准备+路由篇】
本文我们将进行第二步:接口封装
众所周知,接口是一个项目中最重要的能力之一,一个好的接口封装,能让我们与后端的合作更加顺畅
下面我们将开始介绍如何封装一个接口:
具体步骤
下载依赖
相信很多人用的都是axios这个库吧,我们也是主要根据这个库进行封装
yarn add axios
封装一个http方法
我们将在这个方法中,进行请求拦截、响应拦截、登录态校验、接口错误自动重试、接口是否需要完整数据配置、接口是否需要统一异常拦截
请求+响应拦截
我们这里创建了一个axios的实例,并在实例中注入接口请求的URL、超时时间等配置,然后再拿出请求拦截+响应拦截,最后将实例通过一个方法给暴露出去
import axios from "axios";
// 取到对应的环境变量url
export const baseURL = import.meta.env.VITE_BASE_API;
// 创建一个axios实例
const request = axios.create({
baseURL,
timeout: 5000,
withCredentials: true // 浏览器是否应该发送凭据(如 cookies、授权头等)到跨域请求的服务器
});
// 请求拦截器
request.interceptors.request.use((config) => {
return config;
}, (error) => {
return Promise.reject(error);
})
// 响应拦截器
request.interceptors.response.use((response) => {
return response.data;
}, (error) => {
return Promise.reject(error);
})
// 将方法封装成一个函数
const http = async (config: any): Promise<any> => {
return request(config).then((res: IResponse) => {
return res;
}).catch(res => {
return Promise.reject(res);
});
}
export default http;
请求拦截token携带
在请求前,将token给放在请求头上,我这里是放在Authorization上,且这里可以采用自己想用的token存取方式
在http.ts文件里修改:
......
// 请求拦截器
request.interceptors.request.use((config) => {
const token = getToken(); // 自定义获取token
if (config?.headers && token) {
config.headers["Authorization"] = token || "";
}
return config;
}, (error) => {
return Promise.reject(error);
})
......
对未登录或者别的特殊的code进行统一处理
在我们正式的项目中,我们一般会跟后端统一规定一个个特殊的code,比如登录code为1000,权限code为1001等等,那么我们这里可以针对这些code进行统一的封装,这样,所有的接口都会统一走这个逻辑
我们这里先声明了一个枚举类型,方便统一管理特殊的code,然后呢,定义一个接口类型,最后在http方法里通过switch case的方式,去对不同的code进行特殊的逻辑处理
......
// 定义一个枚举code
enum ResCode {
notLogin = 1001,
notPower = 1002,
// ... 其他状态码
}
// 定义一个接口类型
export interface IResponse<T = any> {
code?: number;
data?: T;
msg?: string;
}
// 将方法封装成一个函数
const http = async (config: any): Promise<any> => {
return request(config).then((res: IResponse) => {
switch (res.code) {
case ResCode.notLogin:
// 未登录
// window.location.href = '/login';
break;
case ResCode.notPower:
// 无权限
// window.location.href = '/403';
break;
}
return res;
}).catch(res => {
return Promise.reject(res);
});
}
......
对接口的数据+错误提示信息统一拦截
在我们日常的项目中,我们通常很多时候,不需要上述接口返回的code、data、msg等,只需要data即可,我们这里可以走一个配置,配置默认只返回data;
以及对异常的code走一个统一的提示,因为在实际的项目中,我们不可能对每一个异常code都写一遍逻辑,首先,会有很多重复的工作量,其次,也可能会遗漏掉一些特殊的code的判断;
当然我们也要提前跟后端规定好,正确情况下的code值,比如0;
// 自定义配置
interface IAxiosParam extends AxiosRequestConfig<any> {
/**
* 接口是否需要完整的res,默认不需要,直接返回res.data
*/
needRes?: boolean;
/**
* 接口异常时是否进行统一拦截提示
*/
noAlert?: boolean;
}
// 将方法封装成一个函数
const http = async (config: IAxiosParam): Promise<any> => {
return request(config).then((res: IResponse) => {
switch (res.code) {
case ResCode.notLogin:
// 未登录
// window.location.href = '/login';
break;
case ResCode.notPower:
// 无权限
// window.location.href = '/403';
break;
}
if (res.code !== 0 && !config.noAlert) {
// 异常提示
alert(res.msg || '出现问题啦~');
return;
}
return config.needRes ? res : res.data;
}).catch(res => {
return Promise.reject(res);
});
}
接口失败自动重试
这里我们使用个第三方依赖:axios-retry
yarn add axios-retry
然后直接用就行,还是比较简单的,通过axiosRetry将axios给包裹,并给出自动重试的次数
import axios, { AxiosRequestConfig } from "axios";
import axiosRetry from "axios-retry";
axiosRetry(axios, { retries: 3 });
重复接口拦截
这里可以详细看我这篇文章实战:针对慢网的一些实践与探索,保证不让你失望滴
使用
这里我们已经封装完毕,可以开始使用啦
我们在service的文件下写上代码:
踩踩坑
这里好像暂时没有碰到什么坑~
总结
本文主要介绍了如何封装脚手架的接口模块,包括防止重复请求、自动重试、接口拦截器等等等,较为简单实用,而且我在自己的实际demo中,也并没有遇到什么样的坑,欢迎大家尝试、建议!!!!