axios.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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. " ||| " +
  90. error.message;
  91. } catch (error) {
  92. console.log("detailInfo error");
  93. }
  94. window._hmt.push([
  95. "_trackEvent",
  96. location.pathname.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  97. "网络连接异常,请检查网络设置。",
  98. detailInfo,
  99. ]);
  100. return Promise.reject(error);
  101. }
  102. // 这里是返回状态码不为200时候的错误处理
  103. let status = error.response.status;
  104. // 登录失效 跳转登录页面
  105. if (status == 403 || status == 401) {
  106. if (
  107. window.___lastInvalidDate === undefined ||
  108. window.___lastInvalidDate < Date.now() - 1000
  109. ) {
  110. Message.error({
  111. content: "登录失效,请重新登录!",
  112. duration: 15,
  113. closable: true,
  114. });
  115. window.___lastInvalidDate = Date.now();
  116. const redirectUrl = sessionStorage.getItem("redirectUrl");
  117. if (redirectUrl) {
  118. Modal.error({
  119. title: "确认返回",
  120. content: "token失效",
  121. onOk: () => {
  122. window.location = redirectUrl;
  123. },
  124. });
  125. } else {
  126. router.push("/login/");
  127. }
  128. }
  129. wk_token = null;
  130. // router.push("/login/" + localStorage.getItem("domain"));
  131. return; // 仅显示登录失效,不显示因登录失效造成的后续错误
  132. } else if (status == 502) {
  133. window._hmt.push([
  134. "_trackEvent",
  135. location.pathname.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  136. "服务器异常(502)!",
  137. error.config.url.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  138. ]);
  139. Message.error({
  140. content: "服务器异常(502)!",
  141. duration: 15,
  142. closable: true,
  143. });
  144. return Promise.reject(error);
  145. } else if (status == 503) {
  146. const deal503Apis = [
  147. "/api/ecs_oe_student/examControl/checkExamInProgress",
  148. "/api/branch_ecs_oe_admin/examControl/queryExamList",
  149. ];
  150. if (deal503Apis.includes(error.config.url)) {
  151. return Promise.resolve({ status: 503 });
  152. }
  153. window._hmt.push([
  154. "_trackEvent",
  155. location.pathname.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  156. "服务器繁忙(503)!请稍后重试。",
  157. error.config.url.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  158. ]);
  159. Message.error({
  160. content: "服务器繁忙(503)!请稍后重试。",
  161. duration: 15,
  162. closable: true,
  163. });
  164. return Promise.reject(error);
  165. } else if (status != 200) {
  166. window._hmt.push([
  167. "_trackEvent",
  168. location.pathname.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  169. "status: " + status,
  170. error.config.url.replace(/=\w*/g, "=").replace(/\d+/g, "{id}"),
  171. ]);
  172. if (
  173. wk_token &&
  174. ![401, 403].includes(status) &&
  175. !error.config.url.includes("/api/ecs_core/log/studentClient/")
  176. ) {
  177. setTimeout(() => {
  178. qmInstance.post(
  179. "/api/ecs_core/log/studentClient/" + "debug/S-009001",
  180. error.config.url + " 请求失败",
  181. {
  182. headers: {
  183. "Content-Type": "text/plain",
  184. },
  185. }
  186. );
  187. }, 3 * 1000);
  188. }
  189. const data = error.response.data;
  190. if (data && data.desc) {
  191. Message.error({
  192. content: data.desc,
  193. duration: 15,
  194. closable: true,
  195. });
  196. } else {
  197. Message.error({
  198. content: "未定义异常: " + JSON.stringify(data, 2),
  199. duration: 15,
  200. closable: true,
  201. });
  202. }
  203. }
  204. return Promise.reject(error);
  205. }
  206. );
  207. qmInstance.defaults.withCredentials = true; //允许跨域携带cookie
  208. qmInstance.defaults.timeout = 30 * 1000; //超时时间
  209. qmInstance.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; //标识这是一个 ajax 请求
  210. qmInstance.get = cachingGet(qmInstance.get, [
  211. /\/api\/exam_question\/question\/\?question_id/,
  212. /\/api\/exam_question\/paper_struct\/\?exam_record_id=/,
  213. /\/api\/ecs_oe_student\/examQuestion\/getQuestionContent\?questionId=.*&exam_record_id=/,
  214. // /\/api\/ecs_exam_work\/exam\/\d+$/,
  215. // /\/api\/ecs_oe_student_face\/upyun$/,
  216. /\/api\/ecs_oe_student\/examFaceLivenessVerify\/checkFaceLiveness$/,
  217. ]);
  218. loadProgressBar(qmInstance);
  219. Vue.prototype.$http = qmInstance;
  220. // Vue.prototype.$upyunhttp = upyunInstance;
  221. export default {
  222. install: function (Vue) {
  223. Object.defineProperty(Vue.prototype, "$http", {
  224. value: qmInstance,
  225. });
  226. // Object.defineProperty(Vue.prototype, "$upyunhttp", {
  227. // value: upyunInstance
  228. // });
  229. },
  230. };