axios.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. import Vue from "vue";
  2. import axios from "axios";
  3. import router from "../router";
  4. import { loadProgressBar } from "axios-progress-bar";
  5. import networkInformationHint from "./networkInformationHint.js";
  6. const ERROR_MSG_CONFIG = require("./errorMsgConfig").default;
  7. // Full config: https://github.com/axios/axios#request-config
  8. // axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
  9. // axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
  10. // axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
  11. let config = {
  12. // baseURL: process.env.baseURL || process.env.apiUrl || ""
  13. timeout: 60 * 1000, // Timeout
  14. withCredentials: true, // Check cross-site Access-Control
  15. };
  16. const _$httpWith500Msg = axios.create(config);
  17. const _$http = axios.create(config); // no auto 500 error UI
  18. const _$httpWithoutBar = axios.create(config);
  19. const noauthUrls = ["/auth/login", "/auth/version", "/auth/thirdPartyAccess"];
  20. /**
  21. * A. token lifecycle
  22. * 1. /login UI => localStorage.removeItem('token') && localStorage.setItem('token')
  23. * 2. non /login UI => axios if(!wk_token) wk_token = window.sessionStorage.getItem("token"), send request
  24. * 3. if axios request fail with 401/403, wk_token = null, redirect to /login removeItem('token')
  25. * 4. logout to /login, before send request, invalidate wk_token
  26. * */
  27. let wk_token, wk_key;
  28. let wk_orgId;
  29. function getRootOrgId() {
  30. if (location.hostname.includes("qmth.com.cn")) {
  31. return "";
  32. } else {
  33. return "?orgId=" + (wk_orgId === undefined ? "" : wk_orgId);
  34. }
  35. }
  36. function returnLogin() {
  37. const returnUrl = window.sessionStorage.getItem("returnUrl");
  38. if (returnUrl) {
  39. window.location.href = returnUrl;
  40. return;
  41. }
  42. router.push("/login/" + getRootOrgId());
  43. }
  44. _$httpWith500Msg.interceptors.request.use(
  45. function (config) {
  46. networkInformationHint();
  47. // Do something before request is sent
  48. if (!noauthUrls.some((url) => config.url.includes(url))) {
  49. if (!wk_token) {
  50. const user = JSON.parse(window.sessionStorage.getItem("user"));
  51. if (!user) {
  52. if (
  53. window.___lastInvalidDate === undefined ||
  54. window.___lastInvalidDate < Date.now() - 300
  55. ) {
  56. Vue.prototype.$alert("登录失效,请重新登录!", "提示", {
  57. confirmButtonText: "确定",
  58. callback: () => {
  59. // if (process.env.NODE_ENV !== "production") {
  60. // router.push("/login/" + "?orgId=" + wk_orgId);
  61. // } else {
  62. // router.push("/login");
  63. // }
  64. returnLogin();
  65. },
  66. });
  67. window.___lastInvalidDate = Date.now();
  68. }
  69. return;
  70. }
  71. wk_token = user.token;
  72. wk_key = user.key;
  73. wk_orgId = user.rootOrgId;
  74. }
  75. if (wk_token && config.headers.common["token"] == null) {
  76. config.headers.common["token"] = wk_token;
  77. config.headers.common["key"] = wk_key;
  78. }
  79. } else {
  80. wk_token = null;
  81. }
  82. return config;
  83. },
  84. function (error) {
  85. // Do something with request error
  86. Vue.prototype.$notify({
  87. showClose: true,
  88. message: error,
  89. type: "error",
  90. });
  91. return Promise.reject(error);
  92. }
  93. );
  94. _$http.interceptors.request.use(
  95. // no auto 500 error UI
  96. function (config) {
  97. networkInformationHint();
  98. // Do something before request is sent
  99. if (!noauthUrls.some((url) => config.url.includes(url))) {
  100. if (!wk_token) {
  101. const user = JSON.parse(window.sessionStorage.getItem("user"));
  102. if (!user) {
  103. if (
  104. window.___lastInvalidDate === undefined ||
  105. window.___lastInvalidDate < Date.now() - 300
  106. ) {
  107. Vue.prototype.$alert("登录失效,请重新登录!", "提示", {
  108. confirmButtonText: "确定",
  109. callback: () => {
  110. returnLogin();
  111. },
  112. });
  113. window.___lastInvalidDate = Date.now();
  114. }
  115. return;
  116. }
  117. wk_token = user.token;
  118. wk_key = user.key;
  119. wk_orgId = user.rootOrgId;
  120. }
  121. if (wk_token && config.headers.common["token"] == null) {
  122. config.headers.common["token"] = wk_token;
  123. config.headers.common["key"] = wk_key;
  124. }
  125. } else {
  126. wk_token = null;
  127. }
  128. return config;
  129. },
  130. function (error) {
  131. // Do something with request error
  132. Vue.prototype.$notify({
  133. showClose: true,
  134. message: error,
  135. type: "error",
  136. });
  137. return Promise.reject(error);
  138. }
  139. );
  140. const recordRequest = () => {
  141. let matchedRoutePath;
  142. try {
  143. const matched = router.resolve(location).route.matched;
  144. const exactMatched = matched[matched.length - 1];
  145. matchedRoutePath = exactMatched.path;
  146. } catch (error) {
  147. console.log(error);
  148. window._hmt.push([
  149. "_trackEvent",
  150. `页面-${location.pathname}`,
  151. "网络请求-响应",
  152. "解析出错",
  153. ]);
  154. }
  155. window._hmt.push([
  156. "_trackEvent",
  157. `页面-${matchedRoutePath || location.pathname}`,
  158. "网络请求-响应",
  159. ]);
  160. };
  161. // Add a response interceptor
  162. _$httpWith500Msg.interceptors.response.use(
  163. (response) => {
  164. recordRequest(response);
  165. return response;
  166. },
  167. (error) => {
  168. console.dir(error);
  169. if (!error.response) {
  170. // "Network Error" 网络不通,直接返回
  171. Vue.prototype.$notify({
  172. showClose: true,
  173. message: "网络连接异常,请检查网络设置。",
  174. type: "error",
  175. });
  176. return Promise.reject(error);
  177. }
  178. if (error.config.noToast) {
  179. return Promise.reject(error);
  180. }
  181. // 这里是返回状态码不为200时候的错误处理
  182. let status = error.response.status;
  183. // 登录失效 跳转登录页面
  184. if (status == 403 || status == 401) {
  185. if (
  186. window.___lastInvalidDate === undefined ||
  187. window.___lastInvalidDate < Date.now() - 300
  188. ) {
  189. Vue.prototype.$alert("登录失效,请重新登录!", "提示", {
  190. confirmButtonText: "确定",
  191. callback: () => {
  192. returnLogin();
  193. },
  194. });
  195. window.___lastInvalidDate = Date.now();
  196. }
  197. return Promise.reject(error);
  198. } else if (status == 405) {
  199. Vue.prototype.$alert("没有权限!", "提示", {
  200. confirmButtonText: "确定",
  201. callback: () => {
  202. returnLogin();
  203. },
  204. });
  205. return Promise.reject(error);
  206. } else if (status == 502) {
  207. Vue.prototype.$alert("服务器异常!", "提示", {
  208. confirmButtonText: "确定",
  209. });
  210. return Promise.reject(error);
  211. }
  212. // 下载数据类型为blob时,错误提示直接抛给通用下载逻辑
  213. if (error.response.config.responseType === "blob") {
  214. return Promise.reject(error);
  215. }
  216. if (status != 200) {
  217. const data = error.response.data;
  218. if (ERROR_MSG_CONFIG.map((v) => v.code).includes(data.code)) {
  219. const MSG = ERROR_MSG_CONFIG.find((v) => v.code === data.code);
  220. if (MSG.display) {
  221. Vue.prototype.$notify({
  222. showClose: true,
  223. message: MSG.message,
  224. type: "error",
  225. });
  226. }
  227. } else {
  228. if (data && data.desc) {
  229. Vue.prototype.$notify({
  230. showClose: true,
  231. message: data.desc,
  232. type: "error",
  233. });
  234. } else {
  235. Vue.prototype.$notify({
  236. showClose: true,
  237. message: "未定义异常: " + JSON.stringify(data, 2),
  238. type: "error",
  239. });
  240. }
  241. }
  242. return Promise.reject(error);
  243. }
  244. }
  245. );
  246. // Add a response interceptor
  247. _$http.interceptors.response.use(
  248. // no auto 500 error UI
  249. (response) => {
  250. recordRequest(response);
  251. return response;
  252. },
  253. (error) => {
  254. if (!error.response) {
  255. Vue.prototype.$notify({
  256. showClose: true,
  257. message: "网络连接异常,请检查网络设置。",
  258. type: "error",
  259. });
  260. return Promise.reject(error);
  261. }
  262. if (error.config.noToast) {
  263. return Promise.reject(error);
  264. }
  265. // 这里是返回状态码不为200时候的错误处理
  266. let status = error.response.status;
  267. // 登录失效 跳转登录页面
  268. if (status == 403 || status == 401) {
  269. if (
  270. window.___lastInvalidDate === undefined ||
  271. window.___lastInvalidDate < Date.now() - 300
  272. ) {
  273. Vue.prototype.$alert("登录失效,请重新登录!", "提示", {
  274. confirmButtonText: "确定",
  275. callback: () => {
  276. returnLogin();
  277. },
  278. });
  279. window.___lastInvalidDate = Date.now();
  280. }
  281. return Promise.reject(error);
  282. } else if (status == 405) {
  283. Vue.prototype.$alert("没有权限!", "提示", {
  284. confirmButtonText: "确定",
  285. callback: () => {
  286. returnLogin();
  287. },
  288. });
  289. return Promise.reject(error);
  290. } else if (status == 502) {
  291. Vue.prototype.$alert("服务器异常!", "提示", {
  292. confirmButtonText: "确定",
  293. });
  294. return Promise.reject(error);
  295. } else if (status == 503) {
  296. Vue.prototype.$alert("服务器繁忙,请稍后重试!", "提示", {
  297. confirmButtonText: "确定",
  298. });
  299. return Promise.reject(error);
  300. }
  301. if (status != 200) {
  302. return Promise.reject(error);
  303. }
  304. }
  305. );
  306. _$httpWithoutBar.interceptors.request.use(
  307. // no auto 500 error UI
  308. function (config) {
  309. networkInformationHint();
  310. // Do something before request is sent
  311. if (!noauthUrls.some((url) => config.url.includes(url))) {
  312. if (!wk_token) {
  313. const user = JSON.parse(window.sessionStorage.getItem("user"));
  314. if (!user) {
  315. if (
  316. window.___lastInvalidDate === undefined ||
  317. window.___lastInvalidDate < Date.now() - 300
  318. ) {
  319. Vue.prototype.$alert("登录失效,请重新登录!", "提示", {
  320. confirmButtonText: "确定",
  321. callback: () => {
  322. returnLogin();
  323. },
  324. });
  325. window.___lastInvalidDate = Date.now();
  326. }
  327. return;
  328. }
  329. wk_token = user.token;
  330. wk_key = user.key;
  331. wk_orgId = user.rootOrgId;
  332. }
  333. if (wk_token && config.headers.common["token"] == null) {
  334. config.headers.common["token"] = wk_token;
  335. config.headers.common["key"] = wk_key;
  336. }
  337. } else {
  338. wk_token = null;
  339. }
  340. return config;
  341. },
  342. function (error) {
  343. // Do something with request error
  344. Vue.prototype.$notify({
  345. showClose: true,
  346. message: error,
  347. type: "error",
  348. });
  349. return Promise.reject(error);
  350. }
  351. );
  352. _$httpWithoutBar.interceptors.response.use(
  353. // no auto 500 error UI
  354. (response) => {
  355. recordRequest(response);
  356. return response;
  357. },
  358. (error) => {
  359. if (!error.response) {
  360. Vue.prototype.$notify({
  361. showClose: true,
  362. message: "网络连接异常,请检查网络设置。",
  363. type: "error",
  364. });
  365. return Promise.reject(error);
  366. }
  367. if (error.config.noToast) {
  368. return Promise.reject(error);
  369. }
  370. // 这里是返回状态码不为200时候的错误处理
  371. let status = error.response.status;
  372. // 登录失效 跳转登录页面
  373. if (status == 403 || status == 401) {
  374. if (
  375. window.___lastInvalidDate === undefined ||
  376. window.___lastInvalidDate < Date.now() - 300
  377. ) {
  378. window.___lastInvalidDate = Date.now();
  379. }
  380. return Promise.reject(error);
  381. } else if (status == 405) {
  382. Vue.prototype.$alert("没有权限!", "提示", {
  383. confirmButtonText: "确定",
  384. callback: () => {
  385. returnLogin();
  386. },
  387. });
  388. return Promise.reject(error);
  389. } else if (status == 502) {
  390. Vue.prototype.$alert("服务器异常!", "提示", {
  391. confirmButtonText: "确定",
  392. });
  393. return Promise.reject(error);
  394. }
  395. if (status != 200) {
  396. return Promise.reject(error);
  397. }
  398. }
  399. );
  400. Plugin.install = function (Vue) {
  401. Vue.$http = _$http; // no auto 500 error UI
  402. Object.defineProperties(Vue.prototype, {
  403. $http: {
  404. get() {
  405. return _$http; // no auto 500 error UI
  406. },
  407. },
  408. });
  409. Vue.$httpWithMsg = _$httpWith500Msg;
  410. Object.defineProperties(Vue.prototype, {
  411. $httpWithMsg: {
  412. get() {
  413. return _$httpWith500Msg;
  414. },
  415. },
  416. });
  417. // for below request
  418. // config.url.includes("/api/ecs_ques/paper/") === false &&
  419. // config.url.includes("/api/ecs_ques/questionAudio") === false
  420. const _a = axios.create(config);
  421. Vue.$httpWithoutAuth = _a;
  422. Object.defineProperties(Vue.prototype, {
  423. $httpWithoutAuth: {
  424. get() {
  425. return _a;
  426. },
  427. },
  428. });
  429. Vue.$httpWithoutBar = _$httpWithoutBar;
  430. Object.defineProperties(Vue.prototype, {
  431. $httpWithoutBar: {
  432. get() {
  433. return _$httpWithoutBar;
  434. },
  435. },
  436. });
  437. };
  438. Vue.use(Plugin);
  439. loadProgressBar({}, Vue.$http);
  440. loadProgressBar({}, Vue.$httpWithMsg);
  441. loadProgressBar({}, Vue.$httpWithoutAuth);
  442. // const update = (type, e) => {
  443. // // debugger;
  444. // console.log(type);
  445. // console.log(
  446. // "e.target.url: ",
  447. // e.target.responseURL,
  448. // " timeStamp: ",
  449. // e.timeStamp.toFixed(2),
  450. // " loaded:",
  451. // e.loaded,
  452. // " total: ",
  453. // e.total
  454. // );
  455. // console.log(e);
  456. // };
  457. // Vue.$httpWithMsg.defaults.onDownloadProgress = e => {
  458. // update("下载", e);
  459. // };
  460. // Vue.$httpWithMsg.defaults.onUploadProgress = e => {
  461. // update("上传", e);
  462. // };
  463. import "axios-progress-bar/dist/nprogress.css";
  464. export default Plugin;
  465. export const $httpWithMsg = _$httpWith500Msg;