/** * 基于axios实现的菜鸟基础request库 * axios介绍:https://axios-http.com/zh/docs/intro */ import axios, { AxiosRequestConfig, AxiosInstance, AxiosResponse, AxiosPromise, } from "axios"; import { isUndefined, armsTraceLog, mergeReportData, getCookie } from "./utils"; import { CnOptions, CnLogOptions, CnRequestConfig, CnReportData, CNRequestInstance, CNAxiosInstance, } from "../index.d"; const LEGAL_METHODS = ["GET", "POST"]; const _window = window as any; _window.__cn_request_config = _window.__cn_request_config || { cnOptions: { armsTrace: null, } as CnOptions, axiosConfig: {} as AxiosRequestConfig, }; _window.__cn_request_instance = _window.__cn_request_instance || ({ request: null, reInit(config) { const { cnOptions = {}, axiosConfig = {}, reset = false } = config; if (reset) { _window.__cn_request_config.cnOptions = cnOptions; _window.__cn_request_config.axiosConfig = axiosConfig; } else { _window.__cn_request_config.cnOptions = { ..._window.__cn_request_config.cnOptions, ...cnOptions, }; _window.__cn_request_config.axiosConfig = { ..._window.__cn_request_config.axiosConfig, ...axiosConfig, }; } const axiosInstance = CNRequest( _window.__cn_request_config.axiosConfig, _window.__cn_request_config.cnOptions ); _window.__cn_request_instance.request = axiosInstance; return axiosInstance; }, } as CNRequestInstance); function cnResponseInterceptor( response: AxiosResponse, armsTrace: any = null, options: CnLogOptions ): void { const { turnOffTrace = false, turnOffLog = false, reportResponse = false, cnReportHandler = (data) => { return false; }, } = options; const { success, msg, errorMsg, errorCode, data } = response.data; // 接口格式不符合规范日志打印 if (!turnOffLog) { // 格式校验 if ( isUndefined(success) || isUndefined(msg) || isUndefined(errorMsg) || isUndefined(errorCode) || isUndefined(data) ) { // eslint-disable-next-line no-console console.warn(`接口返回值格式不合法: ${response.request.responseURL}`); console.warn("Evil response.data:", response.data); console.warn( "返回值格式规范请参照: https://yuque.antfin.com/docs/share/18c289e7-7cc9-46d5-aa31-891d18ba168c" ); } } // 是否上报数据 let doReport = false; // 上报的业务数据 let reportData: CnReportData = { errorCode: "-", errorMsg: "-", extend: undefined, reportResponse: reportResponse, }; // 符合规范的业务异常上报 if (success === false) { doReport = true; reportData.errorCode = errorCode ? errorCode : "-"; reportData.errorMsg = errorMsg ? errorMsg : "-"; } // 应用级 自定义业务异常上报 try { if (cnReportHandler instanceof Function) { const _reportData1 = cnReportHandler(response.data); if (_reportData1 instanceof Object) { doReport = true; reportData = mergeReportData(reportData, _reportData1 as CnReportData); } } } catch (error) {} // 接口级 自定义业务异常上报 try { const { cnReportHandler: _cnReportHandler } = response.config as CnRequestConfig; if (_cnReportHandler instanceof Function) { const _reportData2 = _cnReportHandler(response.data); if (_reportData2 instanceof Object) { doReport = true; reportData = mergeReportData(reportData, _reportData2 as CnReportData); } } } catch (error) {} // 若符合上报条件 则执行上报 if (!turnOffTrace && doReport === true && armsTrace) { armsTraceLog(response, armsTrace, reportData); } } function cnRequestInterceptor( config: AxiosRequestConfig, armsTrace: any = null, options: CnLogOptions ): void { const method = config.method.toUpperCase(); const { turnOffLog = false } = options; if (!turnOffLog) { if (!LEGAL_METHODS.includes(method)) { // eslint-disable-next-line no-console console.warn( `使用了不被推荐的请求method:${method};仅推荐 GET 和 POST 两种请求method` ); } } } /** * 基于axios实现的菜鸟基础request库 * @param {axiosConfig} AxiosRequestConfig 初始化axios实例的配置项 * @param {cnOptions} CnOptions 菜鸟业务相关的参数 * @return {AxiosInstance} axios实例,详细查看:https://axios-http.com/zh/docs/instance */ function CNRequest( axiosConfig: AxiosRequestConfig = {}, cnOptions: CnOptions ): CNAxiosInstance { const { armsTrace = null, loginCallback = () => {}, turnOffTrace = false, turnOffLog = false, reportResponse = false, cnReportHandler = (data) => { return false; }, noGlobal = false, } = cnOptions; const logOptions: CnLogOptions = { turnOffTrace, turnOffLog, reportResponse, cnReportHandler, }; const axiosInstance: AxiosInstance = axios.create(axiosConfig); // axios默认会加 // 全局 xsrfToken 处理 // try { // const xsrfToken = getCookie("XSRF-TOKEN"); // if (xsrfToken) { // axiosInstance.defaults.headers.common["X-XSRF-TOKEN"] = xsrfToken; // } // } catch (error) {} axiosInstance.interceptors.request.use( (config: AxiosRequestConfig) => { try { cnRequestInterceptor(config, armsTrace, logOptions); } catch (err) { console.error(`cnRequestInterceptor出错:`, err); } return config; }, (error) => { return Promise.reject(error); } ); axiosInstance.interceptors.response.use( (response: AxiosResponse) => { const { errorCode = "" } = response.data || {}; try { cnResponseInterceptor(response, armsTrace, logOptions); } catch (err) { console.error(`cnResponseInterceptor出错:`, err); } // 未登录执行登录回调 if (errorCode === "1000") { try { loginCallback(); } catch (error) {} } return response; }, (error) => { return Promise.reject(error); } ); return axiosInstance; } function request(options: CnRequestConfig): AxiosPromise { // _window.__cn_request_instance.request 未初始化 则 初始化一次 if (!_window.__cn_request_instance.request) { const axiosInstance = CNRequest( _window.__cn_request_config.axiosConfig, _window.__cn_request_config.cnOptions ); axiosInstance.interceptors.response.use( (response): AxiosResponse | Promise => { const { success = undefined } = response.data || {}; if (success === true) { return response; }else{ // eslint-disable-next-line no-console console.error("business error", response); return Promise.reject(response); } }, (err) => { // eslint-disable-next-line no-console console.error("network error", err); return Promise.reject(err); } ); _window.__cn_request_instance.request = axiosInstance; } return _window.__cn_request_instance.request(options); } function getRequest(): CNAxiosInstance | null { return _window.__cn_request_instance.request; } const cnRequestInstance: CNRequestInstance = _window.__cn_request_instance; const { CancelToken: CancelToken } = axios; export { CancelToken, cnResponseInterceptor, cnRequestInterceptor, cnRequestInstance, request, getRequest, }; export default CNRequest;