|
|
import {
|
|
|
i18n
|
|
|
} from "@/locale";
|
|
|
import {
|
|
|
$uv
|
|
|
} from "@/plugins/ui";
|
|
|
import {
|
|
|
currentRoute,
|
|
|
LOGIN_PATH,
|
|
|
removeQueryString
|
|
|
} from "@/router";
|
|
|
import {
|
|
|
useUserStore
|
|
|
} from "@/store";
|
|
|
import {
|
|
|
useAuthStore
|
|
|
} from "@/store/modules/auth";
|
|
|
import {
|
|
|
ksort
|
|
|
} from "@/utils";
|
|
|
import MD5 from "crypto-js/md5";
|
|
|
|
|
|
// 接口签名
|
|
|
const API_SAFE = false;
|
|
|
const API_KEY = "8oJliIOB2gKdeeLFHec0jmM7Z5S9Y4UdQnP";
|
|
|
// 启用 refreshToken
|
|
|
const ENABLED_REFRESH_TOKEN = false;
|
|
|
// 请求头
|
|
|
const HeaderEnum = {
|
|
|
ACCESS_TOKEN: "Authorization",
|
|
|
REFRESH_TOKEN: "Pass",
|
|
|
I18N: "I18n",
|
|
|
SIGN: "Sign",
|
|
|
};
|
|
|
// code值
|
|
|
const CodeEnum = {
|
|
|
SUCCESS: 200,
|
|
|
ACCESS_TOKEN_INVALID: 4003,
|
|
|
REFRESH_TOKEN_INVALID: 4004,
|
|
|
};
|
|
|
// H5开发环境做跨域处理
|
|
|
let baseURL = import.meta.env.VITE_APP_BASE_URL;
|
|
|
// #ifdef H5
|
|
|
if (import.meta.env.DEV) {
|
|
|
baseURL = import.meta.env.VITE_APP_PROXY_PREFIX;
|
|
|
}
|
|
|
// #endif
|
|
|
// 请求重试队列,每一项将是一个待执行的函数形式
|
|
|
let requests = [];
|
|
|
// 是否正在刷新token的标记
|
|
|
let isRefreshing = false;
|
|
|
|
|
|
// 初始化请求配置
|
|
|
$uv.http.setConfig((config) => {
|
|
|
// 域名设置
|
|
|
// config.baseURL = baseURL;
|
|
|
// 全局header
|
|
|
config.header = {};
|
|
|
config.method = "POST";
|
|
|
// 设置为json,返回后会对数据进行一次JSON.parse()
|
|
|
config.dataType = "json";
|
|
|
// #ifndef MP-ALIPAY
|
|
|
config.responseType = "text";
|
|
|
// #endif
|
|
|
// 全局自定义参数默认值
|
|
|
// 注:如果局部custom与全局custom有同名属性,则后面的属性会覆盖前面的属性,相当于Object.assign(全局,局部)
|
|
|
config.custom = {
|
|
|
// 鉴权
|
|
|
auth: true,
|
|
|
// 请求接口展示Loading
|
|
|
loading: false,
|
|
|
// Loading中是否遮罩
|
|
|
loadingMask: true,
|
|
|
// Loading文本
|
|
|
loadingText: "正在加载",
|
|
|
}; // 全局自定义参数默认值
|
|
|
// #ifdef H5 || APP-PLUS || MP-ALIPAY || MP-WEIXIN
|
|
|
config.timeout = 60000;
|
|
|
// #endif
|
|
|
// #ifdef APP-PLUS
|
|
|
// 验证 ssl 证书 仅5+App安卓端支持(HBuilderX 2.3.3+)
|
|
|
config.sslVerify = true;
|
|
|
// #endif
|
|
|
// #ifdef H5
|
|
|
// 跨域请求时是否携带凭证(cookies)仅H5支持(HBuilderX 2.6.15+)
|
|
|
config.withCredentials = false;
|
|
|
// #endif
|
|
|
// #ifdef APP-PLUS
|
|
|
// DNS解析时优先使用ipv4 仅 App-Android 支持 (HBuilderX 2.8.0+)
|
|
|
config.firstIpv4 = false;
|
|
|
// #endif
|
|
|
// 局部优先级高于全局,返回当前请求的task,options。请勿在此处修改options。非必填
|
|
|
// config.getTask = (task, options) => {
|
|
|
// // 相当于设置了请求超时时间500ms
|
|
|
// setTimeout(() => {
|
|
|
// task.abort();
|
|
|
// }, 500);
|
|
|
// };
|
|
|
// 全局自定义验证器。参数为statusCode 且必存在,不用判断空情况。
|
|
|
config.validateStatus = (statusCode) => {
|
|
|
// 若返回false 走响应拦截的错误回调
|
|
|
return statusCode === 200;
|
|
|
};
|
|
|
return config;
|
|
|
});
|
|
|
|
|
|
const guid = () => {
|
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
|
var r = (Math.random() * 16) | 0,
|
|
|
v = c == 'x' ? r : (r & 0x3) | 0x8
|
|
|
return v.toString(16)
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// 请求拦截部分,如配置,每次请求前都会执行
|
|
|
$uv.http.interceptors.request.use(
|
|
|
(config) => {
|
|
|
// loading
|
|
|
if (config.custom.loading) {
|
|
|
uni.showLoading({
|
|
|
title: config.custom.loadingText ?? "正在加载",
|
|
|
mask: config.custom.loadingMask ?? true,
|
|
|
});
|
|
|
}
|
|
|
|
|
|
const method = config.url
|
|
|
config.url = 'https://lift-dev.ruixininfo.com/jsonrpc'
|
|
|
// config.url = useUserStore().adressIp + '/jsonrpc'
|
|
|
const params = config.data
|
|
|
config.data = {
|
|
|
id: guid(),
|
|
|
jsonrpc: '2.0',
|
|
|
method,
|
|
|
params,
|
|
|
session: useAuthStore().accessToken,
|
|
|
// session:'8ef0a67e75d4ebbcbc5bc897024ea160',
|
|
|
timestampin: Date.now().toString()
|
|
|
}
|
|
|
|
|
|
// 引用token
|
|
|
// if (config.custom.auth) {
|
|
|
// const authStore = useAuthStore();
|
|
|
// config.header[HeaderEnum.ACCESS_TOKEN] = authStore.accessToken;
|
|
|
// }
|
|
|
|
|
|
|
|
|
// 生成接口签名
|
|
|
if (API_SAFE) {
|
|
|
// nonce参数用于防止重发攻击
|
|
|
config.params.nonce = $uv.guid(16);
|
|
|
// timestamp参数用于解决nonce随请求次数无限增多的问题
|
|
|
config.params.timestamp = Date.now();
|
|
|
// 将所有请求参数按照字典排序
|
|
|
const signParams = ksort($uv.deepMerge(config.data, config.params));
|
|
|
// 将排序后的参数数组按照 key1=val1&key2=val2 的形式组成字符串,将字符串与API_KEY连接,用md5加密一次(32位小写),得到sign
|
|
|
let signStr = "";
|
|
|
for (const key in signParams) {
|
|
|
signStr += `${key}=${
|
|
|
typeof signParams[key] === "object"
|
|
|
? JSON.stringify(signParams[key])
|
|
|
: signParams[key]
|
|
|
}&`;
|
|
|
}
|
|
|
signStr += API_KEY;
|
|
|
config.header[HeaderEnum.SIGN] = MD5(signStr).toString();
|
|
|
// console.log(signStr);
|
|
|
}
|
|
|
|
|
|
// 国际化标识
|
|
|
// config.header[HeaderEnum.I18N] = i18n.global.locale.value;
|
|
|
|
|
|
// 最后需要将config进行return
|
|
|
// 如果return Promise.reject(config),则会取消本次请求
|
|
|
return config;
|
|
|
},
|
|
|
(config) => {
|
|
|
return Promise.reject(config);
|
|
|
}
|
|
|
);
|
|
|
|
|
|
// 响应拦截,如配置,每次请求结束都会执行本方法
|
|
|
$uv.http.interceptors.response.use(
|
|
|
(response) => {
|
|
|
/* 对响应成功做点什么 可使用async await 做异步操作*/
|
|
|
console.log('response', response)
|
|
|
|
|
|
// 取消loading
|
|
|
if (response.config.custom.loading) {
|
|
|
uni.hideLoading();
|
|
|
}
|
|
|
if (response.data.error.code === 200) {
|
|
|
return response.data.result
|
|
|
} else if (response.data.error.code === 401) {
|
|
|
// redirectToLoginPage()
|
|
|
$uv.toast(response.data.error.message)
|
|
|
return Promise.reject(response.data.error.message)
|
|
|
} else {
|
|
|
$uv.toast(response.data.error.message)
|
|
|
return Promise.reject(response.data.error.message)
|
|
|
}
|
|
|
|
|
|
// 下载文件,直接返回响应对象
|
|
|
// if (response.config.method === "DOWNLOAD") {
|
|
|
// return response;
|
|
|
// }
|
|
|
|
|
|
// 服务器返回的数据 {code:xxx,data:xxx,msg:xxx}
|
|
|
// const {
|
|
|
// code,
|
|
|
// data,
|
|
|
// msg
|
|
|
// } = response.data;
|
|
|
// if (code === CodeEnum.SUCCESS) {
|
|
|
// // 成功
|
|
|
// return data;
|
|
|
// } else if (code === CodeEnum.ACCESS_TOKEN_INVALID) {
|
|
|
// // 短token无效或过期
|
|
|
// const authStore = useAuthStore();
|
|
|
// if (!ENABLED_REFRESH_TOKEN || !authStore.refreshToken) {
|
|
|
// authStore.signOut();
|
|
|
// redirectToLoginPage();
|
|
|
// return Promise.reject(new Error(msg || "access token invalid"));
|
|
|
// } else {
|
|
|
// return new Promise((resolve, reject) => {
|
|
|
// // 将resolve放进重试队列,用一个函数形式来保存,等token刷新后直接执行
|
|
|
// requests.push(() => resolve($uv.http.request(response.config)));
|
|
|
// // 刷新短token
|
|
|
// if (!isRefreshing) {
|
|
|
// isRefreshing = true;
|
|
|
// authStore
|
|
|
// .refresh({
|
|
|
// [HeaderEnum.REFRESH_TOKEN]: authStore.refreshToken,
|
|
|
// })
|
|
|
// .then(() => {
|
|
|
// requests.forEach((request) => request());
|
|
|
// })
|
|
|
// .catch(() => {
|
|
|
// // 捕获长token失效的reject
|
|
|
// authStore.signOut();
|
|
|
// redirectToLoginPage();
|
|
|
// })
|
|
|
// .finally(() => {
|
|
|
// requests = [];
|
|
|
// isRefreshing = false;
|
|
|
// });
|
|
|
// }
|
|
|
// });
|
|
|
// }
|
|
|
// } else if (code === CodeEnum.REFRESH_TOKEN_INVALID) {
|
|
|
// // 长token无效或过期
|
|
|
// return Promise.reject(new Error(msg || "refresh token invalid"));
|
|
|
// } else {
|
|
|
// // 其他错误
|
|
|
// $uv.toast(msg || "系统出错");
|
|
|
// return Promise.reject(new Error(msg || "system error"));
|
|
|
// }
|
|
|
},
|
|
|
(response) => {
|
|
|
console.log(response)
|
|
|
/* 对响应错误做点什么 */
|
|
|
const codeMsg = {
|
|
|
404: "您所请求的资源无法找到",
|
|
|
500: "服务器内部错误,无法完成请求",
|
|
|
};
|
|
|
const errMsg = codeMsg[response.statusCode] ?? "异常错误";
|
|
|
$uv.toast(errMsg);
|
|
|
return Promise.reject(new Error(errMsg));
|
|
|
}
|
|
|
);
|
|
|
|
|
|
// 跳转登录页
|
|
|
function redirectToLoginPage() {
|
|
|
useAuthStore().signOut()
|
|
|
const path = currentRoute();
|
|
|
if (removeQueryString(path) !== LOGIN_PATH) {
|
|
|
$uv.route({
|
|
|
type: "redirectTo",
|
|
|
url: '/page/index/index',
|
|
|
params: {
|
|
|
redirect: encodeURIComponent(path),
|
|
|
},
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
export default $uv.http; |