axios.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import Vue from "vue";
  2. import axios from "axios";
  3. import { loadProgressBar } from "./axiosProgress";
  4. import cachingGet from "./axiosCache";
  5. import { Message, Modal } from "iview";
  6. import router from "../router";
  7. import { createLog } from "@/utils/logger";
  8. //axios配置 start
  9. const qmInstance = axios.create({});
  10. //请求拦截
  11. /**
  12. * A. token lifecycle
  13. * 1. /login UI => localStorage.removeItem('token') && localStorage.setItem('token')
  14. * 2. non /login UI => axios if(!wk_token) wk_token = window.sessionStorage.getItem("token"), send request
  15. * 3. if axios request fail with 401/403, wk_token = null, redirect to /login removeItem('token')
  16. * 4. logout to /login, before send request, invalidate wk_token
  17. * */
  18. let wk_token, wk_key;
  19. qmInstance.interceptors.request.use(
  20. (config) => {
  21. // debugger;
  22. if (
  23. config.url.includes("/login") === false ||
  24. config.url.includes("/api/ecs_core/auth/thirdPartyStudentAccess") ===
  25. false
  26. ) {
  27. // if (!wk_token) {
  28. wk_token = window.sessionStorage.getItem("token");
  29. wk_key = window.localStorage.getItem("key");
  30. // }
  31. if (wk_token && config.headers.common["token"] == null) {
  32. config.headers.common["token"] = wk_token;
  33. // Axios.defaults.headers.common["key"] = window.localStorage.getItem("key");
  34. config.headers.common["key"] = wk_key;
  35. }
  36. } else {
  37. wk_token = null;
  38. }
  39. return config;
  40. },
  41. (error) => {
  42. Message.error({
  43. content: error,
  44. duration: 15,
  45. closable: true,
  46. });
  47. createLog({
  48. action: "axios request",
  49. error: JSON.stringify(error, (key, value) =>
  50. key === "token" ? "" : value
  51. ),
  52. });
  53. return Promise.resolve(error);
  54. }
  55. );
  56. //响应拦截
  57. qmInstance.interceptors.response.use(
  58. (response) => {
  59. return response;
  60. },
  61. (error) => {
  62. console.log("axios response error: " + JSON.stringify(error));
  63. createLog({
  64. action: "axios response",
  65. error: JSON.stringify(error, (key, value) =>
  66. key === "token" ? "" : value
  67. ),
  68. });
  69. if (!error.response) {
  70. // "Network Error" 网络不通,直接返回
  71. // "timeout of 30000ms exceeded" 连接超时,可能是客户端原因,也可能是服务器原因
  72. if (
  73. window.___lastNetworkError === undefined ||
  74. window.___lastNetworkError < Date.now() - 15 * 1000
  75. ) {
  76. Message.error({
  77. content: "网络连接异常,请检查网络设置。",
  78. duration: 15,
  79. closable: true,
  80. });
  81. window.___lastNetworkError = Date.now();
  82. }
  83. // TODO: 由于chrome58不支持navigator.connection.downlink , 所以无法判断客户端网络状况
  84. let detailInfo = "";
  85. try {
  86. (detailInfo += error.config.url
  87. .replace(/=\w*/g, "=")
  88. .replace(/\/\d+\//g, "/{id}/")
  89. .replace(/\/\d+$/g, "/{id}")) +
  90. " ||| " +
  91. error.message;
  92. } catch (error) {
  93. console.log("detailInfo error");
  94. }
  95. window._hmt.push([
  96. "_trackEvent",
  97. location.pathname.replace(/\d+/g, ""),
  98. "网络连接异常,请检查网络设置。",
  99. detailInfo,
  100. ]);
  101. return Promise.reject(error);
  102. }
  103. // 这里是返回状态码不为200时候的错误处理
  104. let status = error.response.status;
  105. // 登录失效 跳转登录页面
  106. if (status == 403 || status == 401) {
  107. if (
  108. window.___lastInvalidDate === undefined ||
  109. window.___lastInvalidDate < Date.now() - 1000
  110. ) {
  111. Message.error({
  112. content: "登录失效,请重新登录!",
  113. duration: 15,
  114. closable: true,
  115. });
  116. window.___lastInvalidDate = Date.now();
  117. const redirectUrl = sessionStorage.getItem("redirectUrl");
  118. if (redirectUrl) {
  119. Modal.error({
  120. title: "确认返回",
  121. content: "token失效",
  122. onOk: () => {
  123. window.location = redirectUrl;
  124. },
  125. });
  126. } else {
  127. router.push("/login/" + localStorage.getItem("domain"));
  128. }
  129. }
  130. wk_token = null;
  131. // router.push("/login/" + localStorage.getItem("domain"));
  132. return; // 仅显示登录失效,不显示因登录失效造成的后续错误
  133. } else if (status == 502) {
  134. window._hmt.push([
  135. "_trackEvent",
  136. location.pathname,
  137. "服务器异常(502)!",
  138. error.config.url,
  139. ]);
  140. Message.error({
  141. content: "服务器异常(502)!",
  142. duration: 15,
  143. closable: true,
  144. });
  145. return Promise.reject(error);
  146. } else if (status == 503) {
  147. const deal503Apis = [
  148. "/api/ecs_oe_student/examControl/checkExamInProgress",
  149. "/api/ecs_oe_admin/examControl/queryExamList",
  150. ];
  151. if (deal503Apis.includes(error.config.url)) {
  152. return Promise.resolve({ status: 503 });
  153. }
  154. window._hmt.push([
  155. "_trackEvent",
  156. location.pathname.replace(/\d+/g, ""),
  157. "服务器繁忙(503)!请稍后重试。",
  158. error.config.url.replace(/\d+/g, ""),
  159. ]);
  160. Message.error({
  161. content: "服务器繁忙(503)!请稍后重试。",
  162. duration: 15,
  163. closable: true,
  164. });
  165. return Promise.reject(error);
  166. } else if (status != 200) {
  167. window._hmt.push([
  168. "_trackEvent",
  169. location.pathname.replace(/\d+/g, ""),
  170. "status: " + status,
  171. error.config.url
  172. .replace(/=\w*/g, "=")
  173. .replace(/\/\d+\//g, "/{id}/")
  174. .replace(/\/\d+$/g, "/{id}"),
  175. ]);
  176. if (
  177. wk_token &&
  178. ![401, 403].includes(status) &&
  179. !error.config.url.includes("/api/ecs_core/log/studentClient/")
  180. ) {
  181. setTimeout(() => {
  182. qmInstance.post(
  183. "/api/ecs_core/log/studentClient/" + "debug/S-009001",
  184. error.config.url + " 请求失败",
  185. {
  186. headers: {
  187. "Content-Type": "text/plain",
  188. },
  189. }
  190. );
  191. }, 3 * 1000);
  192. }
  193. const data = error.response.data;
  194. if (data && data.desc) {
  195. Message.error({
  196. content: data.desc,
  197. duration: 15,
  198. closable: true,
  199. });
  200. } else {
  201. Message.error({
  202. content: "未定义异常: " + JSON.stringify(data, 2),
  203. duration: 15,
  204. closable: true,
  205. });
  206. }
  207. }
  208. return Promise.reject(error);
  209. }
  210. );
  211. qmInstance.defaults.withCredentials = true; //允许跨域携带cookie
  212. qmInstance.defaults.timeout = 30 * 1000; //超时时间
  213. qmInstance.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; //标识这是一个 ajax 请求
  214. qmInstance.get = cachingGet(qmInstance.get, [
  215. /\/api\/exam_question\/paper_struct\/\?exam_record_id=/,
  216. /\/api\/ecs_oe_student\/examQuestion\/getQuestionContent\?questionId=.*&exam_record_id=/,
  217. // /\/api\/ecs_exam_work\/exam\/\d+$/,
  218. // /\/api\/ecs_oe_student_face\/upyun$/,
  219. /\/api\/ecs_oe_student\/examFaceLivenessVerify\/checkFaceLiveness$/,
  220. ]);
  221. loadProgressBar(qmInstance);
  222. Vue.prototype.$http = qmInstance;
  223. // Vue.prototype.$upyunhttp = upyunInstance;
  224. export default {
  225. install: function (Vue) {
  226. Object.defineProperty(Vue.prototype, "$http", {
  227. value: qmInstance,
  228. });
  229. // Object.defineProperty(Vue.prototype, "$upyunhttp", {
  230. // value: upyunInstance
  231. // });
  232. },
  233. };