axios.js 7.6 KB

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