2021-05-13 11:03:32 +08:00
|
|
|
|
import Request from "@/lib/request/index.js";
|
|
|
|
|
import { refreshTokenFn } from "@/api/login.js";
|
|
|
|
|
import storage from "@/utils/storage.js";
|
|
|
|
|
import { md5 } from "@/utils/md5.js";
|
|
|
|
|
import Foundation from "@/utils/Foundation.js";
|
|
|
|
|
import api from "@/config/api.js";
|
|
|
|
|
|
|
|
|
|
import uuid from "@/utils/uuid.modified.js";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 无痛刷新token思路(如果不使用无痛刷新token,忽略此处注释)
|
|
|
|
|
* 看了很多,有个问题一直得不到解决----‘多个接口请求,token失效,如何让获取token只获取一遍’、
|
|
|
|
|
* 于是想到了闭包防抖......
|
|
|
|
|
* 本方案并不是最佳方案,只是给你们提供一种思路。如果你有完美解决方案,可以分享一下
|
|
|
|
|
*/
|
|
|
|
|
const expireToken = []; // 储存过期的token
|
|
|
|
|
|
|
|
|
|
// 防抖闭包来一波
|
|
|
|
|
function getTokenDebounce() {
|
|
|
|
|
let lock = false;
|
|
|
|
|
let success = false;
|
|
|
|
|
return async function () {
|
|
|
|
|
if (!lock) {
|
|
|
|
|
lock = true;
|
2021-05-17 18:19:26 +08:00
|
|
|
|
await refreshTokenFn(storage.getRefreshToken())
|
2021-05-13 11:03:32 +08:00
|
|
|
|
.then((res) => {
|
|
|
|
|
if (res.data.success) {
|
|
|
|
|
let { accessToken, refreshToken } = res.data.result;
|
|
|
|
|
storage.setAccessToken(accessToken);
|
|
|
|
|
storage.setRefreshToken(refreshToken);
|
|
|
|
|
success = true;
|
|
|
|
|
lock = false;
|
|
|
|
|
} else {
|
|
|
|
|
cleanStorage();
|
|
|
|
|
success = false;
|
|
|
|
|
lock = false;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
cleanStorage();
|
|
|
|
|
success = false;
|
|
|
|
|
lock = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
|
// XXX 我只能想到通过轮询来看获取新的token是否结束,有好的方案可以说。一直看lock,直到请求失败或者成功
|
|
|
|
|
const timer = setInterval(() => {
|
|
|
|
|
if (!lock) {
|
|
|
|
|
clearInterval(timer);
|
2021-05-17 18:19:26 +08:00
|
|
|
|
|
2021-05-13 11:03:32 +08:00
|
|
|
|
if (success) {
|
|
|
|
|
resolve("success");
|
|
|
|
|
} else {
|
|
|
|
|
cleanStorage();
|
|
|
|
|
resolve("fail");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, 100); // 轮询时间可以自己看改成多少合适
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function cleanStorage() {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: "你的登录状态已过期,请重新登录",
|
|
|
|
|
icon: "none",
|
|
|
|
|
duration: 1500,
|
|
|
|
|
});
|
2021-05-17 18:19:26 +08:00
|
|
|
|
if (uni.showLoading()) {
|
|
|
|
|
uni.hideLoading();
|
|
|
|
|
}
|
2021-05-13 11:03:32 +08:00
|
|
|
|
|
|
|
|
|
storage.setHasLogin(false);
|
|
|
|
|
storage.setAccessToken("");
|
|
|
|
|
storage.setRefreshToken("");
|
2021-06-11 17:58:49 +08:00
|
|
|
|
console.log("清空token")
|
2021-05-13 11:03:32 +08:00
|
|
|
|
storage.setUuid("");
|
|
|
|
|
storage.setUserInfo({});
|
|
|
|
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: "/pages/passport/login",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let http = new Request();
|
|
|
|
|
const refreshToken = getTokenDebounce();
|
|
|
|
|
|
|
|
|
|
http.setConfig((config) => {
|
|
|
|
|
// 没有uuid创建
|
|
|
|
|
if (!storage.getUuid()) {
|
|
|
|
|
storage.setUuid(uuid.v1());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 设置全局配置 */
|
|
|
|
|
config.baseURL = api.buyer;
|
|
|
|
|
config.header = {
|
|
|
|
|
...config.header,
|
|
|
|
|
};
|
|
|
|
|
config.validateStatus = (statusCode) => {
|
|
|
|
|
// 不论什么状态,统一在正确中处理
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
return config;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
http.interceptors.request.use(
|
|
|
|
|
(config) => {
|
|
|
|
|
/* 请求之前拦截器。可以使用async await 做异步操作 */
|
|
|
|
|
let accessToken = storage.getAccessToken();
|
|
|
|
|
if (accessToken) {
|
|
|
|
|
const nonce = Foundation.randomString(6);
|
|
|
|
|
const timestamp = parseInt(new Date().getTime() / 1000);
|
|
|
|
|
const sign = md5(nonce + timestamp + accessToken);
|
|
|
|
|
const _params = {
|
|
|
|
|
nonce,
|
|
|
|
|
timestamp,
|
|
|
|
|
sign,
|
|
|
|
|
};
|
|
|
|
|
let params = config.params || {};
|
|
|
|
|
params = { ...params, ..._params };
|
2021-05-21 16:47:26 +08:00
|
|
|
|
|
2021-05-13 11:03:32 +08:00
|
|
|
|
config.params = params;
|
|
|
|
|
config.header.accessToken = accessToken;
|
2021-06-11 17:58:49 +08:00
|
|
|
|
console.warn(accessToken);
|
2021-06-08 18:46:25 +08:00
|
|
|
|
/**
|
|
|
|
|
* jwt 因为安卓以及ios没有window的属性
|
|
|
|
|
* window.atob()这个函数 base64编码的使用方法就是btoa(),而用于解码的使用方法是atob(),
|
|
|
|
|
* 所以使用手写 base-64 编码的字符串数据。
|
|
|
|
|
*/
|
|
|
|
|
const atob = (str) => Buffer.from(str, "base64").toString("binary");
|
|
|
|
|
// 判断如果过期时间小于我的当前时间,在请求上重新刷新token
|
|
|
|
|
if (accessToken.split(".").length <= 1) {
|
|
|
|
|
refresh();
|
|
|
|
|
} else {
|
2021-06-11 17:58:49 +08:00
|
|
|
|
console.log(
|
|
|
|
|
JSON.parse(atob(accessToken.split(".")[1])).exp,
|
|
|
|
|
Math.round(new Date() / 1000)
|
|
|
|
|
);
|
2021-06-08 18:46:25 +08:00
|
|
|
|
if (
|
|
|
|
|
JSON.parse(atob(accessToken.split(".")[1])).exp <
|
2021-06-11 17:58:49 +08:00
|
|
|
|
Math.round(new Date() / 1000)
|
2021-06-08 18:46:25 +08:00
|
|
|
|
) {
|
2021-06-11 17:58:49 +08:00
|
|
|
|
console.log("过期时间小于当前时间刷新token");
|
2021-06-08 18:46:25 +08:00
|
|
|
|
refresh();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-05-13 11:03:32 +08:00
|
|
|
|
}
|
|
|
|
|
config.header = {
|
|
|
|
|
...config.header,
|
|
|
|
|
uuid: storage.getUuid() || uuid.v1(),
|
|
|
|
|
};
|
|
|
|
|
return config;
|
|
|
|
|
},
|
|
|
|
|
(config) => {
|
|
|
|
|
return Promise.reject(config);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2021-06-08 18:46:25 +08:00
|
|
|
|
async function refresh() {
|
|
|
|
|
// 本地储存的是过期token了,重新获取
|
|
|
|
|
const getTokenResult = await refreshToken();
|
2021-06-11 17:58:49 +08:00
|
|
|
|
if (getTokenResult === "success") {
|
|
|
|
|
// 获取新的token成功 刷新当前页面
|
|
|
|
|
|
|
|
|
|
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
|
|
|
|
|
let curRoute = routes[routes.length - 1].route; //获取当前页面路由
|
|
|
|
|
let curParam = routes[routes.length - 1].options; //获取路由参数
|
|
|
|
|
// 拼接参数
|
|
|
|
|
let param = "";
|
|
|
|
|
for (let key in curParam) {
|
|
|
|
|
param += "&" + key + "=" + curParam[key];
|
|
|
|
|
}
|
|
|
|
|
// 判断当前路径
|
|
|
|
|
if (curRoute.indexOf("pages/tabbar") == 1) {
|
|
|
|
|
uni.switchTab({
|
|
|
|
|
url: "/" + curRoute + param.replace("&", "?"),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uni.redirectTo({
|
|
|
|
|
url: "/" + curRoute + param.replace("&", "?"),
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-06-08 18:46:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 11:03:32 +08:00
|
|
|
|
// 必须使用异步函数,注意
|
|
|
|
|
http.interceptors.response.use(
|
|
|
|
|
async (response) => {
|
|
|
|
|
/* 请求之后拦截器。可以使用async await 做异步操作 */
|
|
|
|
|
// token存在并且token过期
|
|
|
|
|
let token = storage.getAccessToken();
|
2021-06-07 11:15:47 +08:00
|
|
|
|
if (
|
|
|
|
|
(token && response.statusCode === 403) ||
|
|
|
|
|
response.data.status === 403
|
|
|
|
|
) {
|
2021-05-13 11:03:32 +08:00
|
|
|
|
// jwt token 过期了
|
|
|
|
|
expireToken.push(token); // 把过期token 储存
|
|
|
|
|
const currentToken = storage.getAccessToken();
|
|
|
|
|
if (expireToken.includes(currentToken)) {
|
2021-06-08 18:46:25 +08:00
|
|
|
|
refresh();
|
2021-05-13 11:03:32 +08:00
|
|
|
|
}
|
2021-05-17 18:19:26 +08:00
|
|
|
|
// 如果当前返回没登录
|
2021-06-07 11:15:47 +08:00
|
|
|
|
} else if (
|
|
|
|
|
(!token && response.statusCode === 403) ||
|
|
|
|
|
response.data.code === 403
|
|
|
|
|
) {
|
2021-05-13 11:03:32 +08:00
|
|
|
|
cleanStorage();
|
2021-05-17 18:19:26 +08:00
|
|
|
|
// 如果当前状态码为正常但是success为不正常时
|
2021-06-07 11:15:47 +08:00
|
|
|
|
} else if (
|
|
|
|
|
(response.statusCode == 200 && !response.data.success) ||
|
|
|
|
|
response.statusCode == 400
|
|
|
|
|
) {
|
|
|
|
|
if (response.data.message) {
|
|
|
|
|
uni.showToast({
|
|
|
|
|
title: response.data.message,
|
|
|
|
|
icon: "none",
|
|
|
|
|
duration: 1500,
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-05-13 11:03:32 +08:00
|
|
|
|
}
|
|
|
|
|
return response;
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
2021-05-21 16:47:26 +08:00
|
|
|
|
return error;
|
2021-05-13 11:03:32 +08:00
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
export { http };
|
|
|
|
|
|
|
|
|
|
export const Method = {
|
|
|
|
|
GET: "GET",
|
|
|
|
|
POST: "POST",
|
|
|
|
|
PUT: "PUT",
|
|
|
|
|
DELETE: "DELETE",
|
|
|
|
|
};
|