一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
前言
在昨天的更文活动中我们已经实现了响应体的优化与白名单的响应码处理。今天我们丰富一下登录的相关逻辑
登录的需求分
脱离业务的开发就是纯粹的浪费时间,我们这里列举几个常见的登录的场景
- 需要用户进入登录页面
这个业务场景是很常见的。例如我们想将一些OA的操作放在小程序上,对于刚开始运行的小程序来说用户的openId是无法获取到的,此时就需要我们在需要获取当前人信息的时候进行以下操作。
判断当前uri是否需要登录->如果需要登录就从缓存获取token数据->封装token至请求头中进行访问
在第二步的获取token的操作中,如果没有获取到就跳转至登录页面。如果获取到了token,但是在请求后端的响应中还是返回401或者403,此时也需要进入登录页面 - 不需要用户进入登录页面
这个业务场景是比较少见的,但是有一些需求就是比较特别。例如我们现在的需求是这样,只要你能进入小程序,我只拿着openId作为你的唯一id,其他的信息我都不需要,这时我们的业务逻辑为
判断当前uri是否需要登录->如果需要登录就从缓存获取token数据->封装token至请求头中进行访问
在第二步的获取token的操作中,如果没有获取到就通过code获取openId,根据openId查询用户,没有就创建用户然后返回用户信息。如果获取到了token,但是在请求后端的响应中还是返回401或者403,重复使用code获取当前用户的操作
对于一些用户不太认可或者不熟悉的小程序来说,第二种往往是用的比较多的,例如你玩的小游戏,就没有几个需要输入手机号和验证码登录的,往往是获取完用户信息之后就直接可以玩了
我们今天主要讨论一下不需要用户登录的场景
我在最后会贴出我的代码,下面先说一下实现的步骤
step1 定义白名单
我们的业务场景中有些页面是不需要登录的,例如电商场景下的登录,商品搜索等
step2 非白名单从缓存中获取token
获取到token的时候就继续访问接口,未获取到的时候就使用code自动登录(可以缓存跳转至登录页来实现用户登录之后才能获取token)
step3 401、403响应码的处理
后端返回401或者403时我们直接删除token,重新调用一次request的方法即可(这里如果一直401小程序会崩溃掉,我们这里添加限制次数)
import Taro from "@tarojs/taro";
const white_res_code = [200, 10001, 10002];
const white_uri = ["/auth/login"];
import { loginByCode } from "../api/user";
function getTokenByApi() {
return new Promise((resolve) => {
Taro.login({
success: (res) => {
loginByCode(res.code).then((res) => {
resolve(res["token"]);
});
},
});
});
}
async function request(url, data, method): Promise<any> {
let notNeedTokenflag =
white_uri.filter((item) => url.includes(item)).length > 0;
let token = Taro.getStorageSync("token");
if (!notNeedTokenflag && (!token || token === "")) {
token = await getTokenByApi();
Taro.setStorageSync("token", token);
}
const header = {
"content-type": "application/json",
};
if (!notNeedTokenflag) {
header["Authorization"] = `Bearer ${token}`;
}
return new Promise((resolve) => {
let retryCount = Taro.getStorageSync("returCount") || 0;
if (retryCount >= 10) {
setTimeout(() => {
Taro.removeStorageSync("returCount");
}, 5000);
return Taro.showToast({
title: "您已被限制5秒内不可以访问接口",
icon: "none",
});
}
Taro.request({
url,
data,
method,
header,
})
.then((res) => {
if (res.statusCode === 200) {
const backEndRes = res.data;
const resCode = backEndRes.code;
if (!white_res_code.includes(resCode)) {
switch (resCode) {
case 500:
return Taro.showToast({
title: "请求失败,系统异常:" + backEndRes.msg,
icon: "none",
});
case 401:
Taro.removeStorageSync("token");
Taro.setStorageSync("returCount", retryCount + 1);
request(url, data, method);
return Taro.showToast({
title: "请求失败,请您登陆:" + backEndRes.msg,
icon: "none",
});
case 403:
Taro.removeStorageSync("token");
Taro.setStorageSync("returCount", retryCount + 1);
request(url, data, method);
return Taro.showToast({
title: "请求失败,暂无权限:" + backEndRes.msg,
icon: "none",
});
default:
return Taro.showToast({
title: "请求失败:" + res.data.error,
icon: "none",
});
}
} else {
resolve(backEndRes.data);
}
resolve(res.data);
} else {
Taro.showToast({ title: "请求失败:" + res.data.error, icon: "none" });
}
})
.catch((err) => {
Taro.showToast({ title: "网络错误,提示:" + err.errMsg, icon: "none" });
});
});
}
function get(url) {
return request(url, null, "GET");
}
function post(url, data) {
return request(url, data, "POST");
}
function del(url) {
return request(url, null, "DELETE");
}
function put(url, data) {
return request(url, data, "POST");
}
export { get, post, del, put };
结语
今天时间不是特别充裕,明天想一下要写啥。欢迎大家多多关注!