基于 axios 1.5.0的二次封装
目录结构
server 根目录
├── defaultConfig.ts 默认配置
├── index.ts 入口文件
├── RequestBase.ts 具体封装文件
├── requestInterceptor 请求拦截器
│ ├── index.ts 收集所有拦截器
│ └── interceptors
│ └── defaultHandler.ts 默认拦截器
├── responseInterceptor 响应拦截器
│ ├── index.ts 收集所有拦截器
│ └── interceptors
│ ├── defaultHandler.ts 默认拦截器
│ └── parseDataHandler.ts 默认拦截器打印参数拦截器
└── type.ts 类型定义
type.ts 一些自定义的类型
import { AxiosRequestConfig, AxiosResponseHeaders, RawAxiosResponseHeaders } from "axios";
/**
* 自定义的请求配置信息,继承axios自带的配置
*/
export interface RequestConfig extends AxiosRequestConfig {
// 是否打印请求和响应时的信息
isPrintFetchInfo?: boolean;
// 是否打印请求信息
isPrintReqFetchInfo?: boolean;
// 是否打印响应信息
isPrintResFetchInfo?: boolean;
// 是否只返回请求的结果
onlyData?: boolean;
// 请求结果是否输出错误信息
isShowErrorInfo?: boolean;
}
// RequestBase 使用到
export interface Response {
data: Result;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: RequestConfig;
request?: any;
}
/**
* 后端的返回结构
*/
export interface Result<T = any> {
code: string;
innercode: string;
datetime: string;
message: T;
}
RequestBase.ts 具体的封装
import axios, {
AxiosInstance,
CreateAxiosDefaults,
AxiosRequestConfig,
InternalAxiosRequestConfig,
AxiosError
} from "axios";
import { RequestConfig, Response } from "./type";
export default class RequestBase {
private readonly instance: AxiosInstance;
private request!: Request;
/**
* 初始化axios
* @param defaultConfig 请求的默认配置
*/
constructor(defaultConfig: CreateAxiosDefaults) {
const instance = axios.create(defaultConfig);
// 初始化请求对象
const methods: Method[] = ["get", "post", "put", "patch", "delete"];
const request: Request = {} as Request;
methods.forEach(method => {
request[method] = (url: string, options?: RequestConfig) => {
options = options || {};
options.method = method;
options.url = url;
return instance(url, options);
};
});
this.request = request;
this.instance = instance;
}
/**
* 返回请求对象
* @returns
*/
getInstance() {
return this.request;
}
/**
* 添加一个请求拦截器
* @param handle 请求拦截处理
*/
addRequestInterceptor(handle: RequestHandle) {
let onFulfilled: RequestFulfilled;
let onRejected: Rejected | undefined;
switch (typeof handle) {
case "function":
onFulfilled = handle;
break;
case "object":
onFulfilled = handle.onFulfilled;
onRejected = handle.onRejected;
break;
default:
throw new Error("请求拦截器定义错误: " + handle);
}
this.instance.interceptors.request.use((config: AxiosRequestConfig) => {
return onFulfilled(config as any) as InternalAxiosRequestConfig;
}, onRejected);
}
/**
* 添加一个响应拦截器
* @param handle 响应处理
*/
addResponseInterceptor(handle: ResponseHandle) {
let onFulfilled: ResponseFulfilled;
let onRejected: Rejected | undefined;
switch (typeof handle) {
case "function":
onFulfilled = handle;
break;
case "object":
onFulfilled = handle.onFulfilled;
onRejected = handle.onRejected;
break;
default:
throw new Error("请求拦截器定义错误: " + handle);
}
this.instance.interceptors.response.use(onFulfilled as any, onRejected);
}
setBaseURL(baseURL: string) {
this.instance.defaults.baseURL = baseURL;
}
}
type Method = "get" | "post" | "put" | "patch" | "delete";
type Request = {
[key in Method]: <T = any>(url: string, options?: RequestConfig) => Promise<T>;
};
// 请求拦截器处理类型,可以是一个function作为成功处理,或者一个对象存储成功与失败处理
export type RequestHandle = RequestFulfilled | RequestInterceptor;
// 响应拦截器处理类型,可以是一个function作为成功处理,或者一个对象存储成功与失败处理
export type ResponseHandle = ResponseFulfilled | ResponseInterceptor;
// 请求成功与失败的处理
export interface RequestInterceptor {
onFulfilled: RequestFulfilled;
onRejected?: Rejected;
}
// 响应成功和失败的处理
export interface ResponseInterceptor {
onFulfilled: ResponseFulfilled;
onRejected?: Rejected;
}
// 请求拦截器成功的处理
export type RequestFulfilled = (options: RequestConfig) => RequestConfig;
// 响应拦截器成功的处理
export type ResponseFulfilled = (response: Response) => any;
// 请求失败
type Rejected = (error: AxiosError) => any;
defaultConfig.ts 默认配置
import { RequestConfig } from "./type";
// 默认请求配置
const defaultConfig: RequestConfig = {
timeout: 1000 * 10,
headers: {
"Content-Type": "application/json"
// "Access-Control-Allow-Origin ": "*"
},
// 是否打印输出信息,优先级高于下面两个
isPrintFetchInfo: true,
// 是否打印返回数据
isPrintResFetchInfo: true,
// 是否打印请求配置
isPrintReqFetchInfo: false,
// 默认只返回数据
onlyData: true,
// 是否输出错误信息
isShowErrorInfo: true
};
export default defaultConfig;
requestInterceptor 请求拦截器
index.ts
用于收集所有请求拦截器在server/index.ts中应用
import { RequestHandle } from "../RequestBase";
import defaultHandler from "./interceptors/defaultHandler";
const requestInterceptors: RequestHandle[] = [defaultHandler];
export default requestInterceptors;
interceptors 存放请求拦截器
可自定义一些请求拦截器
defaultHandler.ts 默认拦截器
import { RequestInterceptor } from "./../../RequestBase";
/**
* 默认拦截器,负责打印数据
*/
const defaultHandler: RequestInterceptor = {
onFulfilled: config => {
const {
baseURL = "",
url,
data,
method,
params,
isPrintFetchInfo,
isPrintReqFetchInfo
} = config;
const isGet = method === "get";
const info = isGet ? params : data;
if (isPrintFetchInfo && isPrintReqFetchInfo) {
console.log(
`from 请求拦截器-成功: \nurl: ${baseURL + url}`,
"\nconfig:",
config,
`\nparams: `,
info
);
}
return config;
},
onRejected: error => {
console.log("from 请求拦截器-失败: ", error);
Promise.reject(error);
}
};
export default defaultHandler;
responseInterceptor 响应拦截器
可自定义一些响应拦截器
index.ts
用于收集所有响应拦截器在server/index.ts中应用
import { ResponseHandle, ResponseInterceptor, ResponseFulfilled } from "./../RequestBase";
import parseDateHandler from "./interceptors/parseDataHandler";
import defaultHandler from "./interceptors/defaultHandler";
/**
* 收集拦截器
*/
const responseInterceptor: ResponseHandle[] = [defaultHandler, parseDateHandler];
export default responseInterceptor;
interceptors 存放响应拦截器
defaultHandler.ts 默认拦截器
import { ResponseInterceptor } from "./../../RequestBase";
/**
* 默认拦截器,负责打印数据
*/
const defaultHandler: ResponseInterceptor = {
onFulfilled: res => {
const { config, data } = res;
const { baseURL = "", url, isPrintFetchInfo, isPrintResFetchInfo } = config;
if (!(isPrintFetchInfo && isPrintResFetchInfo)) {
return;
}
const fullUrl = baseURL + url;
const { message } = data;
console.log(
`from 响应拦截器-成功: \nurl: ${fullUrl} \nres: `,
res,
"\nfetchResult:",
data,
"\ndata: ",
message
);
return res;
},
onRejected: error => {
console.log("from 响应拦截器-失败: \n请求失败: ", error);
return Promise.reject(error);
}
};
export default defaultHandler;
parseDataHandler.ts 解析返回值拦截器
import { ResponseInterceptor } from "../../RequestBase";
import { Message } from "element-ui";
/**
* 解析数据拦截器
*/
const parseDateHandler: ResponseInterceptor = {
onFulfilled: res => {
const { config, data } = res;
const { onlyData, isShowErrorInfo } = config;
const { code, message } = data;
if (code === "0000") {
// 只返回用到的数据
if (onlyData) {
return message;
}
return data;
}
if (isShowErrorInfo) {
const info = typeof message === "string" ? message : "好像出错啦!";
Message({
message: info,
type: "error"
});
}
return Promise.reject(res);
},
onRejected: error => {
Message.error("好像出错啦!");
return Promise.reject(error);
}
};
export default parseDateHandler;
index 请求对象入口文件
import { CreateAxiosDefaults } from "axios";
import RequestBase from "./RequestBase";
import requestInterceptor from "./requestInterceptor";
import responseInterceptor from "./responseInterceptor";
import { RequestConfig } from "./type";
import defaultConfig from "./defaultConfig";
const request = new RequestBase(defaultConfig);
// 添加请求拦截器
requestInterceptor.forEach(e => {
request.addRequestInterceptor(e);
});
// 添加响应拦截器
responseInterceptor.forEach(e => {
request.addResponseInterceptor(e);
});
// 返回请求对象
export const setBaseURL = (baseURL: string) => {
console.log("baseURL: " + baseURL);
request.setBaseURL(baseURL);
};
export default request.getInstance();
例子
import request from "xxx/server"
/**
* get请求
*/
function getTest(target): Promise<IResult[]> {
const url = "xxxx";
const params = {
target
};
return request.get(url, { params });
}
/**
* post请求,关闭控制台输出请求参数和响应结果
*/
function postTest(target): Promise<IResult[]> {
const url = "xxxx";
const data = {
target
};
return request.post(url, { data, isPrintFetchInfo: false });
}
/**
* 定义后端返回的数据,用于ts类型提示
*/
interface IResult {
age: number;
address: string;
}
// 具体使用
getTest(1).then(e => {
// e被推导为 IResult 结构
e.age = "dsa"; //Type 'number' is not assignable to type 'string'
})