index.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. * @Author: Gui
  3. * @Date: 2023-03-01 19:20:44
  4. * @LastEditors: guicheng 1625811865@qq.com
  5. * @LastEditTime: 2024-04-16 16:39:24
  6. * @Description: tel files
  7. * @filePath:
  8. */
  9. import Axios, {
  10. AxiosInstance,
  11. AxiosRequestConfig,
  12. CustomParamsSerializer
  13. } from "axios";
  14. import {
  15. PureHttpError,
  16. RequestMethods,
  17. PureHttpResponse,
  18. PureHttpRequestConfig
  19. } from "./types.d";
  20. import { stringify } from "qs";
  21. import NProgress from "../progress";
  22. import { getConfig } from "@/config";
  23. import { getToken, formatToken, removeToken } from "@/utils/auth";
  24. import { useUserStoreHook } from "@/store/modules/user";
  25. import { ElMessage } from "element-plus";
  26. import encryptByDES from "@/utils/encryptByDES";
  27. import regExpTest from "@/utils/FilterSensitiveWords";
  28. import { storageLocal, storageSession, toggleClass } from "@pureadmin/utils";
  29. import { useAppStoreHook } from "@/store/modules/app";
  30. import router, { resetRouter } from "@/router";
  31. import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
  32. import { routerArrays } from "@/layout/types";
  33. import { dataResult } from "@/api/apiResult";
  34. // 相关配置请参考:www.axios-js.com/zh-cn/docs/#axios-request-config-1
  35. const defaultConfig: AxiosRequestConfig = {
  36. // 请求超时时间
  37. timeout: 500000,
  38. headers: {
  39. Accept: "application/json, text/plain, */*",
  40. "Content-Type": "application/json",
  41. "X-Requested-With": "XMLHttpRequest"
  42. },
  43. // 数组格式参数序列化(https://github.com/axios/axios/issues/5142)
  44. paramsSerializer: {
  45. serialize: stringify as unknown as CustomParamsSerializer
  46. }
  47. };
  48. class PureHttp {
  49. constructor() {
  50. this.httpInterceptorsRequest();
  51. this.httpInterceptorsResponse();
  52. }
  53. /** token过期后,暂存待执行的请求 */
  54. private static requests = [];
  55. /** 防止重复刷新token */
  56. private static isRefreshing = false;
  57. /** 初始化配置对象 */
  58. private static initConfig: PureHttpRequestConfig = {};
  59. /** 保存当前Axios实例对象 */
  60. private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);
  61. /** 重连原始请求 */
  62. private static retryOriginalRequest(config: PureHttpRequestConfig) {
  63. return new Promise(resolve => {
  64. PureHttp.requests.push((token: string) => {
  65. config.headers["Authorization"] = formatToken(token);
  66. resolve(config);
  67. return config;
  68. });
  69. });
  70. }
  71. /** 请求拦截 */
  72. private httpInterceptorsRequest(): void {
  73. PureHttp.axiosInstance.interceptors.request.use(
  74. async (config: PureHttpRequestConfig) => {
  75. // 开启进度条动画
  76. NProgress.start();
  77. // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
  78. if (typeof config.beforeRequestCallback === "function") {
  79. config.beforeRequestCallback(config);
  80. return config;
  81. }
  82. if (PureHttp.initConfig.beforeRequestCallback) {
  83. PureHttp.initConfig.beforeRequestCallback(config);
  84. return config;
  85. }
  86. /** 请求白名单,放置一些不需要token的接口(通过设置请求白名单,防止token过期后再请求造成的死循环问题) */
  87. const whiteList = ["/refreshtoken", "/login"];
  88. return whiteList.some(v => config.url.indexOf(v) > -1)
  89. ? config
  90. : new Promise(resolve => {
  91. const data = getToken();
  92. if (data) {
  93. const now = new Date().getTime();
  94. const expired = parseInt(data.expires) - now <= 0;
  95. if (expired) {
  96. if (!PureHttp.isRefreshing) {
  97. PureHttp.isRefreshing = true;
  98. // token过期刷新
  99. // apiToken
  100. // apiTokenExpiredDate
  101. // refreshToken
  102. useUserStoreHook()
  103. .handRefreshToken({ refreshToken: data.refreshToken })
  104. .then(res => {
  105. const token = res.data.apiToken;
  106. config.headers["Authorization"] = formatToken(token);
  107. PureHttp.requests.forEach(cb => cb(token));
  108. PureHttp.requests = [];
  109. })
  110. .finally(() => {
  111. PureHttp.isRefreshing = false;
  112. });
  113. }
  114. resolve(PureHttp.retryOriginalRequest(config));
  115. } else {
  116. config.headers["Authorization"] = formatToken(
  117. data.accessToken
  118. );
  119. resolve(config);
  120. }
  121. } else {
  122. resolve(config);
  123. }
  124. });
  125. },
  126. error => {
  127. return Promise.reject(error);
  128. }
  129. );
  130. }
  131. /** 响应拦截 */
  132. private httpInterceptorsResponse(): void {
  133. const instance = PureHttp.axiosInstance;
  134. instance.interceptors.response.use(
  135. (response: PureHttpResponse) => {
  136. const $config = response.config;
  137. // 关闭进度条动画
  138. NProgress.done();
  139. // 优先判断post/get等方法是否传入回掉,否则执行初始化设置等回掉
  140. if (typeof $config.beforeResponseCallback === "function") {
  141. $config.beforeResponseCallback(response);
  142. return response.data;
  143. }
  144. if (PureHttp.initConfig.beforeResponseCallback) {
  145. PureHttp.initConfig.beforeResponseCallback(response);
  146. return response.data;
  147. }
  148. return response.data;
  149. },
  150. (error: PureHttpError) => {
  151. if (error.response.status === 401) {
  152. ElMessage({
  153. message: `用户token失效,请重新登录`,
  154. type: "error"
  155. });
  156. setTimeout(() => {
  157. removeToken();
  158. storageLocal().clear();
  159. storageSession().clear();
  160. const { Grey, Weak, Layout } = getConfig();
  161. useAppStoreHook().setLayout(Layout);
  162. toggleClass(Grey, "html-grey", document.querySelector("html"));
  163. toggleClass(Weak, "html-weakness", document.querySelector("html"));
  164. resetRouter();
  165. router.push("/login");
  166. useMultiTagsStoreHook().handleTags("equal", [...routerArrays]);
  167. }, 2000);
  168. }
  169. const $error = error;
  170. $error.isCancelRequest = Axios.isCancel($error);
  171. // 关闭进度条动画
  172. NProgress.done();
  173. // 所有的响应异常 区分来源为取消请求/非取消请求
  174. return Promise.reject($error);
  175. }
  176. );
  177. }
  178. /** 登录请求工具函数 */
  179. public login<T>(
  180. url: string,
  181. param?: any,
  182. axiosConfig?: PureHttpRequestConfig
  183. ): Promise<T> {
  184. //本地调试配置
  185. url = url.replace("http://logic-executor-api.kexiaoshuang.com", "/aapi")
  186. const config = {
  187. method: "post",
  188. url:
  189. url +
  190. "?scope=server&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer",
  191. data: encryptByDES(JSON.stringify(param)),
  192. auth: {
  193. username: "admin",
  194. password: "kmdlqkyuvl"
  195. },
  196. headers: {
  197. "Content-Type": "application/json"
  198. },
  199. ...axiosConfig
  200. } as PureHttpRequestConfig;
  201. // 单独处理自定义请求/响应回掉
  202. return new Promise((resolve, reject) => {
  203. console.log(
  204. "[ 请求地址 ] >",
  205. url +
  206. "?scope=server&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer"
  207. );
  208. console.log("[ 加密前 ] >", param);
  209. console.log("[ 加密后 ] >", encryptByDES(JSON.stringify(param)));
  210. PureHttp.axiosInstance
  211. .request(config)
  212. .then((response: undefined) => {
  213. resolve(response);
  214. })
  215. .catch(error => {
  216. reject(error);
  217. });
  218. });
  219. }
  220. /** 通用请求工具函数 */
  221. public request(
  222. method: RequestMethods,
  223. url: string,
  224. param?: any,
  225. axiosConfig?: PureHttpRequestConfig
  226. ): any {
  227. //本地调试配置
  228. url = url.replace("http://logic-executor-api.kexiaoshuang.com", "/aapi")
  229. const config = {
  230. method,
  231. url,
  232. ...param,
  233. headers: {
  234. "Content-Type": "application/json"
  235. },
  236. ...axiosConfig
  237. } as PureHttpRequestConfig;
  238. // 单独处理自定义请求/响应回掉
  239. // console.log(config);
  240. return new Promise((resolve, reject) => {
  241. PureHttp.axiosInstance
  242. .request(config)
  243. .then((response: undefined) => {
  244. resolve(response);
  245. })
  246. .catch(error => {
  247. reject(error);
  248. });
  249. });
  250. }
  251. /** 单独抽离的post工具函数 */
  252. public post<T>(
  253. url: string,
  254. params?: AxiosRequestConfig<T>,
  255. config?: PureHttpRequestConfig
  256. ): any {
  257. let legal = true;
  258. const paramskey = [];
  259. for (const key in params) {
  260. if (
  261. params[key] &&
  262. typeof params[key] === "string" &&
  263. regExpTest(params[key])
  264. ) {
  265. paramskey.push(key);
  266. legal = false;
  267. }
  268. }
  269. if (legal) {
  270. const param = { data: encryptByDES(JSON.stringify(params)) };
  271. return this.request("post", url, param, config);
  272. } else {
  273. ElMessage({
  274. message: `params is illegal`,
  275. type: "error"
  276. });
  277. return Promise.reject(`${paramskey.join("、")} is illegal params`);
  278. }
  279. }
  280. /** 单独抽离的post工具函数 */
  281. public Richpost<T>(
  282. url: string,
  283. params?: AxiosRequestConfig<T>,
  284. config?: PureHttpRequestConfig
  285. ): any {
  286. const param = { data: encryptByDES(JSON.stringify(params)) };
  287. return this.request("post", url, param, config);
  288. }
  289. /** 单独抽离的get工具函数 */
  290. public get<T>(
  291. url: string,
  292. params?: AxiosRequestConfig<T>,
  293. config?: PureHttpRequestConfig
  294. ): any {
  295. let legal = true;
  296. const paramskey = [];
  297. for (const key in params) {
  298. if (
  299. params[key] &&
  300. typeof params[key] === "string" &&
  301. regExpTest(params[key])
  302. ) {
  303. paramskey.push(key);
  304. legal = false;
  305. }
  306. }
  307. if (legal) {
  308. console.log("[ 请求地址 ] >", url);
  309. console.log("[ 加密前 ] >", params);
  310. const paramter = { value: encryptByDES(JSON.stringify(params)) };
  311. const param = { params: paramter };
  312. console.log("[ 加密后 ] >", paramter);
  313. return this.request("get", url, param, config);
  314. } else {
  315. ElMessage({
  316. message: `params is illegal`,
  317. type: "error"
  318. });
  319. return Promise.reject(`${paramskey.join("、")} is illegal params`);
  320. }
  321. }
  322. /** 单独抽离的put工具函数 */
  323. public put<T>(
  324. url: string,
  325. params?: AxiosRequestConfig<T>,
  326. config?: PureHttpRequestConfig
  327. ): any {
  328. let legal = true;
  329. const paramskey = [];
  330. console.log('dddd', params);
  331. for (const key in params) {
  332. if (
  333. params[key] &&
  334. typeof params[key] === "string" &&
  335. regExpTest(params[key])
  336. ) {
  337. paramskey.push(key);
  338. legal = false;
  339. }
  340. }
  341. if (legal) {
  342. const param = { data: encryptByDES(JSON.stringify(params)) };
  343. return this.request("put", url, param, config);
  344. } else {
  345. ElMessage({
  346. message: `params is illegal`,
  347. type: "error"
  348. });
  349. return Promise.reject(`${paramskey.join("、")} is illegal params`);
  350. }
  351. }
  352. /** 单独抽离的delete工具函数 */
  353. public delete<T>(
  354. url: string,
  355. params?: AxiosRequestConfig<T>,
  356. config?: PureHttpRequestConfig
  357. ): dataResult {
  358. const param = { data: {} };
  359. console.log('ddd', params);
  360. return this.request(
  361. "delete",
  362. `${url}/${encryptByDES(params)}`,
  363. param,
  364. config
  365. );
  366. }
  367. public Request(param: any): dataResult {
  368. const method = param.method.toUpperCase();
  369. switch (method) {
  370. case "GET":
  371. return this.get(param.url, param.params, param.config);
  372. break;
  373. case "POST":
  374. return this.post(param.url, param.params, param.config);
  375. break;
  376. case "DELETE":
  377. return this.delete(param.url, param.params, param.config);
  378. break;
  379. case "PUT":
  380. return this.put(param.url, param.params, param.config);
  381. break;
  382. case "RICHPOST":
  383. return this.Richpost(param.url, param.params, param.config);
  384. break;
  385. }
  386. }
  387. }
  388. export const http = new PureHttp();