| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| /** |
| * Manipulate APIs(操作Api) |
| */ |
| import util from '@/common/util'; |
| import axios from 'axios'; |
| import { Message } from 'iview'; |
| import cache from './apiCache'; |
| import i18n from '../../common/i18n' |
| |
| // what an array is used to store the cancel function and id for each request(什么一个数组用于存储每个请求的取消函数和标识) |
| let pending = []; |
| let cancelConfig = null; |
| let CancelToken = axios.CancelToken; |
| let removePending = (config) => { |
| for (let p = 0; p < pending.length; p++) { |
| const params = JSON.stringify(config.params); |
| // Cancel if it exists(如果存在则执行取消操作) |
| if (pending[p].u === config.url + '&' + config.method + '&' + params) { |
| // pending[p].f();// perform cancellation(执行取消操作) |
| pending.splice(p, 1);// remove record(移除记录) |
| } |
| } |
| }; |
| |
| let cutReq = (config) => { |
| for (let p = 0; p < pending.length; p++) { |
| const params = JSON.stringify(config.params); |
| if (pending[p].u === config.url + '&' + config.method + '&' + params) { |
| return true; |
| } |
| } |
| }; |
| |
| const instance = axios.create({ |
| baseURL: process.env.VUE_APP_MN_CONFIG_PREFIX || `${window.location.protocol}//${window.location.host}/api/rest_j/v1/`, |
| timeout: 600000, |
| withCredentials: true, |
| headers: { 'Content-Type': 'application/json;charset=UTF-8' }, |
| }); |
| |
| instance.interceptors.request.use((config) => { |
| // Add internationalization parameters(增加国际化参数) |
| config.headers['Content-language'] = localStorage.getItem('locale') || 'zh-CN'; |
| let flag = cutReq(config); |
| // The second same request cannot be made when the last same request is not completed(当上一次相同请求未完成时,无法进行第二次相同请求) |
| if (flag === true) { |
| removePending(config); |
| return config; |
| } else { |
| const params = JSON.stringify(config.params); |
| // It is used to remove when there is an error in the normal request(用于正常请求出现错误时移除) |
| cancelConfig = config; |
| config.cancelToken = new CancelToken((c) => { |
| // Add identity and cancel functions(添加标识和取消函数) |
| pending.push({ |
| u: config.url + '&' + config.method + '&' + params, |
| f: c, |
| }); |
| }); |
| return config; |
| } |
| }, (error) => { |
| Promise.reject(error); |
| }); |
| |
| instance.interceptors.response.use((response) => { |
| // Perform the cancellation operation after an ajax response is successful, and remove the completed request from the pending(在一个ajax响应成功后再执行取消操作,把已完成的请求从pending中移除) |
| removePending(response.config); |
| return response; |
| }, (error) => { |
| // Judgment when an interface exception or timeout occurs(出现接口异常或者超时时的判断) |
| if ((error.message && error.message.indexOf('timeout') >= 0) || (error.request && error.request.status !== 200)) { |
| for (let p in pending) { |
| if (pending[p].u === cancelConfig.url + '&' + cancelConfig.method + '&' + JSON.stringify(cancelConfig.params)) { |
| pending.splice(p, 1);// remove record(移除记录) |
| } |
| } |
| // The error information returned by the background is returned first, followed by the interface return(优先返回后台返回的错误信息,其次是接口返回) |
| return error.response || error; |
| } else if (axios.Cancel) { |
| // If it is in pengding state, a prompt will pop up!(如果是pengding状态,弹出提示!) |
| return { |
| // data: { message: 'Interface requesting! please wait……' }(data: { message: '接口请求中!请稍后……' }) |
| }; |
| } else { |
| return error; |
| } |
| }); |
| |
| const api = { |
| instance: instance, |
| error: { |
| '-1': function (res) { |
| if (res.data && res.data.enableSSO && res.data.SSOURL) { |
| return window.location.replace(res.data.SSOURL); |
| } |
| |
| const isLoginPath = window.location.hash == "#/login"; |
| if (!isLoginPath) { |
| window.location.hash = "#/login"; |
| throw new Error('您尚未登录,请先登录!'); |
| } |
| }, |
| }, |
| constructionOfResponse: { |
| codePath: 'status', |
| successCode: '0', |
| messagePath: 'message', |
| resultPath: 'data' |
| }, |
| }; |
| |
| const getData = function (data) { |
| let _arr = ['codePath', 'messagePath', 'resultPath']; |
| let res = {}; |
| _arr.forEach((item) => { |
| let pathArray = api.constructionOfResponse[item].split('.'); |
| let result = pathArray.length === 1 && pathArray[0] === '*' ? data : data[pathArray[0]]; |
| for (let j = 1; j < pathArray.length; j++) { |
| result = result[pathArray[j]]; |
| if (!result) { |
| if (j < pathArray.length - 1) { |
| window.console.error(`【FEX】ConstructionOfResponse配置错误:${item}拿到的值是undefined,请检查配置`); |
| } |
| break; |
| } |
| } |
| res[item] = result; |
| }); |
| return res; |
| }; |
| |
| const success = function (response) { |
| if (util.isNull(api.constructionOfResponse.codePath) || util.isNull(api.constructionOfResponse.successCode) || |
| util.isNull(api.constructionOfResponse.messagePath) || util.isNull(api.constructionOfResponse.resultPath)) { |
| window.console.error('【FEX】Api配置错误: 请调用setConstructionOfResponse来设置API的响应结构'); |
| return; |
| } |
| let data; |
| if (response) { |
| const linkis_errorMsgTip = (sessionStorage.getItem('linkis.errorMsgTip') || '').replace(/%s/g, response.config.url) |
| if (util.isString(response.data)) { |
| data = JSON.parse(response.data); |
| } else if (util.isObject(response.data)) { |
| data = response.data; |
| } else { |
| throw new Error(linkis_errorMsgTip || i18n.t('message.common.exceptionTips')); |
| } |
| let res = getData(data); |
| let code = res.codePath; |
| let message = res.messagePath; |
| let result = res.resultPath; |
| let errorMsgTip = result ? result.errorMsgTip : ''; |
| if (errorMsgTip) { |
| sessionStorage.setItem('linkis.errorMsgTip', errorMsgTip) |
| } |
| if (code != api.constructionOfResponse.successCode) { |
| if (api.error[code]) { |
| api.error[code](response); |
| throw new Error(''); |
| } else { |
| throw new Error(message || linkis_errorMsgTip || i18n.t('message.common.exceptionTips')); |
| } |
| } |
| if (result) { |
| let len = 0 |
| let hasBigData = Object.values(result).some(item => { |
| if (Array.isArray(item)) { |
| len = item.length > len ? item.length : len |
| return len > 200 |
| } |
| }) |
| if (hasBigData) { |
| window.console.log(response.data, '潜在性能问题大数据量', len) |
| } |
| } |
| |
| return result || {}; |
| } |
| }; |
| |
| const fail = function (error) { |
| let _message = ''; |
| let response = error.response; |
| if (response && api.error[response.status]) { |
| api.error[response.status].forEach((fn) => fn(response)); |
| } else { |
| _message = i18n.t('message.common.exceptionTips'); |
| if (response && response.config) _message = (sessionStorage.getItem('linkis.errorMsgTip') || '').replace(/%s/g, response.config.url) || i18n.t('message.common.exceptionTips'); |
| if (response && response.data) { |
| let data; |
| if (util.isString(response.data)) { |
| data = JSON.parse(response.data); |
| } else if (util.isObject(response.data)) { |
| data = response.data; |
| } |
| if (data) { |
| let res = getData(data); |
| _message = res.messagePath; |
| } |
| } |
| } |
| error.message = _message; |
| throw error; |
| }; |
| |
| const param = function (url, data, option) { |
| let method = 'post'; |
| if (util.isNull(url)) { |
| return window.console.error('请传入URL'); |
| } else if (!util.isNull(url) && util.isNull(data) && util.isNull(option)) { |
| option = { |
| method: method, |
| }; |
| } else if (!util.isNull(url) && !util.isNull(data) && util.isNull(option)) { |
| option = { |
| method: method, |
| }; |
| if (util.isString(data)) { |
| option.method = data; |
| } else if (util.isObject(data)) { |
| option.data = data; |
| } |
| } else if (!util.isNull(url) && !util.isNull(data) && !util.isNull(option)) { |
| if (!util.isObject(data)) { |
| data = {}; |
| } |
| if (util.isString(option)) { |
| option = { |
| method: option, |
| }; |
| } else if (util.isObject(option)) { |
| option.method = option.method || method; |
| } else { |
| option = { |
| method: method, |
| }; |
| } |
| if (option.method == 'get' || option.method == 'delete' || option.method == 'head' || option.method == 'options') { |
| option.params = data; |
| } |
| if (option.method == 'post' || option.method == 'put' || option.method == 'patch') { |
| option.data = data; |
| } |
| } |
| // cacheOptions interface data cache {time} When the time is 0, the data cached in the memory will not be cleaned up after the request(cacheOptions接口数据缓存 {time} time为0则请求之后缓存在内存里的数据不清理) |
| if (option.cacheOptions) { |
| option.adapter = cache(option.cacheOptions) |
| } |
| option.url = url; |
| |
| return instance.request(option); |
| }; |
| |
| const action = function (url, data, option) { |
| return param(url, data, option) |
| .then(success, fail) |
| .then(function (response) { |
| return response; |
| }) |
| .catch(function (error) { |
| if (error.message) { |
| let urlReg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/g; |
| let result = error.message.match(urlReg); |
| result ? Message.error({ |
| duration: 3, |
| render: h => { |
| let context = error.message.split(result[0]); |
| return h('span', [ |
| context[0], |
| h('a', { |
| domProps: { |
| href: result[0], |
| target: '_blank' |
| }, |
| }, result[0]), |
| context[1], |
| ]) |
| } |
| }) : Message.error({ |
| duration: 1.5, |
| content: error.message |
| }); |
| } |
| throw error; |
| }); |
| }; |
| |
| api.fetch = action; |
| |
| api.option = function (option) { |
| if (option.root) { |
| instance.defaults.baseURL = option.root; |
| } |
| if (option.timeout && util.isNumber(option.timeout)) { |
| instance.defaults.timeout = option.timeout; |
| } |
| if (option.config && util.isObject(option.config)) { |
| Object.keys(option.config).forEach(function (key) { |
| instance.defaults[key] = option.config[key]; |
| }); |
| } |
| }; |
| |
| api.setError = function (option) { |
| if (option && util.isObject(option)) { |
| util.merge(api.error, option); |
| } |
| }; |
| |
| api.setResponse = function (constructionOfResponse) { |
| this.constructionOfResponse = constructionOfResponse; |
| }; |
| |
| export default api; |