TS二次封装axios-自用

349 阅读4分钟

基于 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'
})