import Vue from "vue"; import axios from "axios"; import { loadProgressBar } from "./axiosProgress"; import cachingGet from "./axiosCache"; import { Message, Modal } from "iview"; import router from "../router"; import { createLog } from "@/utils/logger"; //axios配置 start const qmInstance = axios.create({}); //请求拦截 /** * A. token lifecycle * 1. /login UI => localStorage.removeItem('token') && localStorage.setItem('token') * 2. non /login UI => axios if(!wk_token) wk_token = window.sessionStorage.getItem("token"), send request * 3. if axios request fail with 401/403, wk_token = null, redirect to /login removeItem('token') * 4. logout to /login, before send request, invalidate wk_token * */ let wk_token, wk_key; qmInstance.interceptors.request.use( (config) => { // debugger; if ( config.url.includes("/login") === false || config.url.includes("/api/ecs_core/auth/thirdPartyStudentAccess") === false ) { // if (!wk_token) { wk_token = window.sessionStorage.getItem("token"); wk_key = window.localStorage.getItem("key"); // } if (wk_token && config.headers.common["token"] == null) { config.headers.common["token"] = wk_token; // Axios.defaults.headers.common["key"] = window.localStorage.getItem("key"); config.headers.common["key"] = wk_key; } } else { wk_token = null; } return config; }, (error) => { Message.error({ content: error, duration: 15, closable: true, }); createLog({ action: "axios request", error: JSON.stringify(error, (key, value) => key === "token" ? "" : value ), }); return Promise.resolve(error); } ); //响应拦截 qmInstance.interceptors.response.use( (response) => { return response; }, (error) => { console.log("axios response error: " + JSON.stringify(error)); createLog({ action: "axios response", error: JSON.stringify(error, (key, value) => key === "token" ? "" : value ), }); if (!error.response) { // "Network Error" 网络不通,直接返回 // "timeout of 30000ms exceeded" 连接超时,可能是客户端原因,也可能是服务器原因 if ( window.___lastNetworkError === undefined || window.___lastNetworkError < Date.now() - 15 * 1000 ) { Message.error({ content: "网络连接异常,请检查网络设置。", duration: 15, closable: true, }); window.___lastNetworkError = Date.now(); } // TODO: 由于chrome58不支持navigator.connection.downlink , 所以无法判断客户端网络状况 let detailInfo = ""; try { (detailInfo += error.config.url .replace(/=\w*/g, "=") .replace(/\/\d+\//g, "/{id}/") .replace(/\/\d+$/g, "/{id}")) + " ||| " + error.message; } catch (error) { console.log("detailInfo error"); } window._hmt.push([ "_trackEvent", location.pathname.replace(/\d+/g, ""), "网络连接异常,请检查网络设置。", detailInfo, ]); return Promise.reject(error); } // 这里是返回状态码不为200时候的错误处理 let status = error.response.status; // 登录失效 跳转登录页面 if (status == 403 || status == 401) { if ( window.___lastInvalidDate === undefined || window.___lastInvalidDate < Date.now() - 1000 ) { Message.error({ content: "登录失效,请重新登录!", duration: 15, closable: true, }); window.___lastInvalidDate = Date.now(); const redirectUrl = sessionStorage.getItem("redirectUrl"); if (redirectUrl) { Modal.error({ title: "确认返回", content: "token失效", onOk: () => { window.location = redirectUrl; }, }); } else { router.push("/login/" + localStorage.getItem("domain")); } } wk_token = null; // router.push("/login/" + localStorage.getItem("domain")); return; // 仅显示登录失效,不显示因登录失效造成的后续错误 } else if (status == 502) { window._hmt.push([ "_trackEvent", location.pathname, "服务器异常(502)!", error.config.url, ]); Message.error({ content: "服务器异常(502)!", duration: 15, closable: true, }); return Promise.reject(error); } else if (status == 503) { const deal503Apis = [ "/api/ecs_oe_student/examControl/checkExamInProgress", "/api/ecs_oe_admin/examControl/queryExamList", ]; if (deal503Apis.includes(error.config.url)) { return Promise.resolve({ status: 503 }); } window._hmt.push([ "_trackEvent", location.pathname.replace(/\d+/g, ""), "服务器繁忙(503)!请稍后重试。", error.config.url.replace(/\d+/g, ""), ]); Message.error({ content: "服务器繁忙(503)!请稍后重试。", duration: 15, closable: true, }); return Promise.reject(error); } else if (status != 200) { window._hmt.push([ "_trackEvent", location.pathname.replace(/\d+/g, ""), "status: " + status, error.config.url .replace(/=\w*/g, "=") .replace(/\/\d+\//g, "/{id}/") .replace(/\/\d+$/g, "/{id}"), ]); if ( wk_token && ![401, 403].includes(status) && !error.config.url.includes("/api/ecs_core/log/studentClient/") ) { setTimeout(() => { qmInstance.post( "/api/ecs_core/log/studentClient/" + "debug/S-009001", error.config.url + " 请求失败", { headers: { "Content-Type": "text/plain", }, } ); }, 3 * 1000); } const data = error.response.data; if (data && data.desc) { Message.error({ content: data.desc, duration: 15, closable: true, }); } else { Message.error({ content: "未定义异常: " + JSON.stringify(data, 2), duration: 15, closable: true, }); } } return Promise.reject(error); } ); qmInstance.defaults.withCredentials = true; //允许跨域携带cookie qmInstance.defaults.timeout = 30 * 1000; //超时时间 qmInstance.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; //标识这是一个 ajax 请求 qmInstance.get = cachingGet(qmInstance.get, [ /\/api\/exam_question\/paper_struct\/\?exam_record_id=/, /\/api\/ecs_oe_student\/examQuestion\/getQuestionContent\?questionId=.*&exam_record_id=/, // /\/api\/ecs_exam_work\/exam\/\d+$/, // /\/api\/ecs_oe_student_face\/upyun$/, /\/api\/ecs_oe_student\/examFaceLivenessVerify\/checkFaceLiveness$/, ]); loadProgressBar(qmInstance); Vue.prototype.$http = qmInstance; // Vue.prototype.$upyunhttp = upyunInstance; export default { install: function (Vue) { Object.defineProperty(Vue.prototype, "$http", { value: qmInstance, }); // Object.defineProperty(Vue.prototype, "$upyunhttp", { // value: upyunInstance // }); }, };