vben
2021-02-22 be3a3ed699f73d352d49623ef07288093a3332c4
提交 | 用户 | age
2f6253 1 // axios配置  可自行根据项目进行更改,只需更改该文件即可,其他文件可以不动
2 // The axios configuration can be changed according to the project, just change the file, other files can be left unchanged
3
4 import type { AxiosResponse } from 'axios';
5 import type { CreateAxiosOptions, RequestOptions, Result } from './types';
6 import { VAxios } from './Axios';
7 import { AxiosTransform } from './axiosTransform';
8
9 import { checkStatus } from './checkStatus';
10
ba068b 11 import { useGlobSetting } from '/@/hooks/setting';
2f6253 12 import { useMessage } from '/@/hooks/web/useMessage';
13
14 import { RequestEnum, ResultEnum, ContentTypeEnum } from '/@/enums/httpEnum';
15
16 import { isString } from '/@/utils/is';
17 import { setObjToUrlParams, deepMerge } from '/@/utils';
710158 18 import { errorStore } from '/@/store/modules/error';
e83cb0 19 import { errorResult } from './const';
190112 20 import { useI18n } from '/@/hooks/web/useI18n';
f646e3 21 import { createNow, formatRequestDate } from './helper';
be3a3e 22 import { userStore } from '/@/store/modules/user';
2f6253 23
737b1b 24 const globSetting = useGlobSetting();
2f6253 25 const prefix = globSetting.urlPrefix;
26 const { createMessage, createErrorModal } = useMessage();
27
28 /**
29  * @description: 数据处理,方便区分多种处理方式
30  */
31 const transform: AxiosTransform = {
32   /**
33    * @description: 处理请求数据
34    */
35   transformRequestData: (res: AxiosResponse<Result>, options: RequestOptions) => {
962f90 36     const { t } = useI18n();
2f6253 37     const { isTransformRequestResult } = options;
38     // 不进行任何处理,直接返回
39     // 用于页面代码可能需要直接获取code,data,message这些信息时开启
40     if (!isTransformRequestResult) {
41       return res.data;
42     }
43     // 错误的时候返回
44
45     const { data } = res;
46     if (!data) {
47       // return '[HTTP] Request has no return value';
48       return errorResult;
49     }
50     //  这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
51     const { code, result, message } = data;
52
53     // 这里逻辑可以根据项目进行修改
54     const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
55     if (!hasSuccess) {
56       if (message) {
57         // errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
58         if (options.errorMessageMode === 'modal') {
962f90 59           createErrorModal({ title: t('sys.api.errorTip'), content: message });
4ce1d5 60         } else if (options.errorMessageMode === 'message') {
2f6253 61           createMessage.error(message);
62         }
63       }
64       Promise.reject(new Error(message));
65       return errorResult;
66     }
67
68     // 接口请求成功,直接返回结果
69     if (code === ResultEnum.SUCCESS) {
e83cb0 70       return result;
2f6253 71     }
72     // 接口请求错误,统一提示错误信息
73     if (code === ResultEnum.ERROR) {
74       if (message) {
75         createMessage.error(data.message);
76         Promise.reject(new Error(message));
77       } else {
962f90 78         const msg = t('sys.api.errorMessage');
2f6253 79         createMessage.error(msg);
80         Promise.reject(new Error(msg));
81       }
82       return errorResult;
83     }
84     // 登录超时
85     if (code === ResultEnum.TIMEOUT) {
962f90 86       const timeoutMsg = t('sys.api.timeoutMessage');
2f6253 87       createErrorModal({
962f90 88         title: t('sys.api.operationFailed'),
2f6253 89         content: timeoutMsg,
90       });
91       Promise.reject(new Error(timeoutMsg));
92       return errorResult;
93     }
94     return errorResult;
95   },
96
97   // 请求之前处理config
98   beforeRequestHook: (config, options) => {
f646e3 99     const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true } = options;
2f6253 100
101     if (joinPrefix) {
102       config.url = `${prefix}${config.url}`;
103     }
104
105     if (apiUrl && isString(apiUrl)) {
106       config.url = `${apiUrl}${config.url}`;
107     }
ac1a36 108     const params = config.params || {};
6b3195 109     if (config.method?.toUpperCase() === RequestEnum.GET) {
ac1a36 110       if (!isString(params)) {
c96002 111         // 给 get 请求加上时间戳参数,避免从缓存中拿数据。
V 112         config.params = Object.assign(params || {}, createNow(joinTime, false));
2f6253 113       } else {
114         // 兼容restful风格
ac1a36 115         config.url = config.url + params + `${createNow(joinTime, true)}`;
34c09f 116         config.params = undefined;
2f6253 117       }
118     } else {
ac1a36 119       if (!isString(params)) {
V 120         formatDate && formatRequestDate(params);
121         config.data = params;
34c09f 122         config.params = undefined;
2f6253 123         if (joinParamsToUrl) {
124           config.url = setObjToUrlParams(config.url as string, config.data);
125         }
126       } else {
127         // 兼容restful风格
ac1a36 128         config.url = config.url + params;
34c09f 129         config.params = undefined;
2f6253 130       }
131     }
132     return config;
133   },
134
135   /**
136    * @description: 请求拦截器处理
137    */
138   requestInterceptors: (config) => {
139     // 请求之前处理config
be3a3e 140     const token = userStore.getTokenState;
2f6253 141     if (token) {
142       // jwt token
143       config.headers.Authorization = token;
144     }
145     return config;
146   },
147
148   /**
149    * @description: 响应错误处理
150    */
151   responseInterceptorsCatch: (error: any) => {
962f90 152     const { t } = useI18n();
710158 153     errorStore.setupErrorHandle(error);
2f6253 154     const { response, code, message } = error || {};
de5bf7 155     const msg: string = response?.data?.error?.message ?? '';
V 156     const err: string = error?.toString?.() ?? '';
2f6253 157     try {
158       if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
962f90 159         createMessage.error(t('sys.api.apiTimeoutMessage'));
2f6253 160       }
6b3195 161       if (err?.includes('Network Error')) {
2f6253 162         createErrorModal({
962f90 163           title: t('sys.api.networkException'),
V 164           content: t('sys.api.networkExceptionMsg'),
2f6253 165         });
166       }
167     } catch (error) {
168       throw new Error(error);
169     }
6b3195 170     checkStatus(error?.response?.status, msg);
661db0 171     return Promise.reject(error);
2f6253 172   },
173 };
174
175 function createAxios(opt?: Partial<CreateAxiosOptions>) {
176   return new VAxios(
177     deepMerge(
178       {
179         timeout: 10 * 1000,
180         // 基础接口地址
181         // baseURL: globSetting.apiUrl,
182         // 接口可能会有通用的地址部分,可以统一抽取出来
183         prefixUrl: prefix,
184         headers: { 'Content-Type': ContentTypeEnum.JSON },
f646e3 185         // 如果是form-data格式
V 186         // headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
2f6253 187         // 数据处理方式
188         transform,
189         // 配置项,下面的选项都可以在独立的接口请求中覆盖
190         requestOptions: {
191           // 默认将prefix 添加到url
192           joinPrefix: true,
193           // 需要对返回数据进行处理
194           isTransformRequestResult: true,
195           // post请求的时候添加参数到url
196           joinParamsToUrl: false,
197           // 格式化提交参数时间
198           formatDate: true,
199           // 消息提示类型
4ce1d5 200           errorMessageMode: 'message',
2f6253 201           // 接口地址
202           apiUrl: globSetting.apiUrl,
f646e3 203           //  是否加入时间戳
V 204           joinTime: true,
2f6253 205         },
206       },
207       opt || {}
208     )
209   );
210 }
211 export const defHttp = createAxios();
212
213 // other api url
214 // export const otherHttp = createAxios({
215 //   requestOptions: {
216 //     apiUrl: 'xxx',
217 //   },
218 // });