近日在使用react+typescript制作项目,发现ts的使用方法与js的差别相当巨大。其中就包括axios的封装方法,网上找的各种教程也没看懂。于是自己花了将近一天的时间,通过各方面的学习,总算自己封装好了一个ts版的axios。因为之前都是使用vue来开发的,所以这个封装好的axios,我想尽量让它的调用的方式跟原来的vue的调用方式差不多,因为我认为原来的调用方式非常美观且易于管理。
//vue的调用方式
import { request } from './request'
//参数是 地址:url、请求参数:params、仅用于当前api的配置config——该参数选填
export const LoginApi = params => request.post('/user/login', params, {timeout: 15000});
...更多的api
为了达到上面的调用方式,于是自己实现了封装。
以下为详细实现方法:
第一步
安装:axios
// -S 意为该依赖包将会打包至生产环境
cnpm i axios -S
第二步
1、在 src 文件夹下新建 api 文件夹——该文件夹可随意命名,不过推荐使用api来命名
2、在 api 文件夹里新建request.ts文件,下为源码(下面的代码可以直接复制出来使用)
import axios, { AxiosRequestConfig, AxiosRequestHeaders } from 'axios';
import { message } from 'antd'
//基础URL,axios将会自动拼接在url前
//process.env.NODE_ENV 判断是否为开发环境 根据不同环境使用不同的baseURL 方便调试
let baseURL = process.env.NODE_ENV === 'development'? '' : 'https://your.domain.com/api';
//默认请求超时时间
const timeout = 30000;
//创建axios实例
const service = axios.create({
timeout,
baseURL,
//如需要携带cookie 该值需设为true
withCredentials: true
});
//统一请求拦截 可配置自定义headers 例如 language、token等
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
//配置自定义请求头
let customHeaders: AxiosRequestHeaders = {
language: 'zh-cn'
};
config.headers = customHeaders;
return config
},
error => {
console.log(error)
Promise.reject(error)
}
)
//axios返回格式
interface axiosTypes<T>{
data: T;
status: number;
statusText: string;
}
//后台响应数据格式
//###该接口用于规定后台返回的数据格式,意为必须携带code、msg以及result
//###而result的数据格式 由外部提供。如此即可根据不同需求,定制不同的数据格式
interface responseTypes<T>{
code: number,
msg: string,
result: T
}
//核心处理代码 将返回一个promise 调用then将可获取响应的业务数据
const requestHandler = <T>(method: 'get' | 'post' | 'put' | 'delete', url: string, params: object = {}, config: AxiosRequestConfig = {}): Promise<T> => {
let response: Promise<axiosTypes<responseTypes<T>>>;
switch(method){
case 'get':
response = service.get(url, {params: { ...params }, ...config});
break;
case 'post':
response = service.post(url, {...params}, {...config});
break;
case 'put':
response = service.put(url, {...params}, {...config});
break;
case 'delete':
response = service.delete(url, {params: { ...params }, ...config});
break;
}
return new Promise<T>((resolve, reject) => {
response.then(res => {
//业务代码 可根据需求自行处理
const data = res.data;
if(data.code !== 200){
//特定状态码 处理特定的需求
if(data.code == 401){
message.warn('您的账号已登出或超时,即将登出...');
console.log('登录异常,执行登出...');
}
let e = JSON.stringify(data);
message.warn(`请求错误:${e}`);
console.log(`请求错误:${e}`)
//数据请求错误 使用reject将错误返回
reject(data);
}else{
//数据请求正确 使用resolve将结果返回
resolve(data.result);
}
}).catch(error => {
let e = JSON.stringify(error);
message.warn(`网络错误:${e}`);
console.log(`网络错误:${e}`)
reject(error);
})
})
}
// 使用 request 统一调用,包括封装的get、post、put、delete等方法
const request = {
get: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('get', url, params, config),
post: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('post', url, params, config),
put: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('put', url, params, config),
delete: <T>(url: string, params?: object, config?: AxiosRequestConfig) => requestHandler<T>('delete', url, params, config)
};
// 导出至外层,方便统一使用
export { request };
3、新建index.ts文件,导出对应的api
import { request } from './request'
//登录
export const LoginApi = <T>(params: any) => request.post<T>('/user/login', params, {timeout: 15000});
如此一来,就能像vue一样导出和调用了
使用示例
import { LoginApi } from '@/api'
interface loginTypes{
auth: Array<string>,
userInfo: {
account: string,
username: string
},
token: string
}
LoginApi<loginTypes>(data).then(res => {
//登录成功。处理区域...
}).catch(err => {
//登录失败。处理区域...
})