微信小程序通过官方登录功能获取用户身份信息,并构建用户体系,极大地简化了用户管理流程。看似简单,但其背后需要前后端协同,涉及诸多操作步骤,值得详细研究。
拥有小程序项目
项目是根本。没有项目,就无从谈起。就好比盖楼前得先有地。现实中,比如开发一个商品展示的小程序,不能没有项目就动手。开发者常选用uni-app来初始化项目。若不熟悉,也可查阅相关资料。此外,若尚未创建项目,必须先完成这一步,这是实现登录功能的前提。只有创建了项目,才能进行后续的登录等操作,这是基础中的基础。不同项目或许有细微差别,但总体步骤是相似的。
开发登录功能,项目是根本,离开了它,登录功能就无法实现。这一点在开发者中普遍认同,没有项目就如同厨师没有炉灶,无法继续进行后续工作。
登录逻辑的最佳时机
用户在使用静音登录时,不会察觉到登录过程,且不会触及到个人隐私信息。这种登录方式最佳的做法是在用户直接访问时立即启动,创建用户会话。以查询天气的小程序为例,用户打开应用即完成登录,获取天气信息时身份已明确。这样的体验相当出色。在uni-app项目的根组件App.vue的生命周期函数中处理登录逻辑非常适宜。这里相当于一个核心节点,负责启动登录流程。
实际操作中,这里的处理方式与小程序运行规则相契合。在已上线的小程序里,这种做法能提升登录速度,用户无需繁琐步骤即可完成关键操作,这对用户留存大有裨益。
Token的存储与处理
export default {
onLaunch: function() {
// 从storage获取登录信息,没有则需要登录
let tokenInfo = uni.getStorageSync("tokenInfo");
let hasValidToken = false;
if (tokenInfo) {
let time = new Date().valueOf();
// 存储时间小于token失效时间,才是有效token, 否则重新授权
hasValidToken = time - tokenInfo.timestamp {
// 获取到code后,提交给服务端
this.$api.post('/wxa/login', {
code: wxInfo.code,
}).then((res) => {
// 存储获取到的token
uni.setStorage({
key: 'tokenInfo',
data: {
token: res.token,
timestamp: new Date().valueOf()
}
})
})
},
});
}
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
将token保存在本地缓存特定键值下。token相当于一张门禁卡,妥善保存后能降低对接口的多次请求。例如,一个网络阅读应用,若频繁调用接口,会降低其运行效率。在保存token的同时,记录时间戳同样关键。若当前时间戳与保存时间戳之差超过30天(此期限可协商),token即失效,需重新登录。
有人提出,若token失效,在调用接口遇到错误码后,只需重新登录即可。然而,通过主动判断,我们能够预先规避不少麻烦。比如,在部分电商小程序里,若因token失效而无法加载商品列表,用户可能会错过抢购等宝贵机会。
携带Token进行其他请求
登录成功后,本地会获取一个token,这个token在后续的请求中必须携带,以便后端识别请求者身份。通常,我们会按照既定规则,将token嵌入到后端接口的域名中。然而,若在每一次请求中都添加这一步骤,无疑会增加大量工作。这好比一场大型活动,后勤人员不可能为每位参会者单独准备七八项手续。
在这种情况下,对请求进行封装显得尤为重要。众多开发者会依据项目的特性以及后端的需求来进行封装操作。这样的做法在众多企业内部使用的办公小程序中,能有效提升工作效率,并保证用户的请求能够得到准确的识别。
错误码的判断逻辑
后端若输出自设的错误码,0表示正常反馈,其他数字则代表异常。在开发阶段,这样的判断标准能有效辅助我们发现问题。比如,在某个游戏小程序里,若玩家在登录或领取奖品时遇到麻烦,我们可以通过错误码迅速确定是前端还是后端出了问题。这对小程序的稳定运行至关重要。
// 该处配置为后端接口地址
const defaultHost = "http://api-server.com";
const errorMsg = (response) => {
let error = {};
if (response.statusCode) {
error.code = response.statusCode;
switch (response.statusCode) {
case 400:
error.msg = "错误请求";
break;
case 401:
error.msg = "未授权,请重新登录";
break;
case 403:
error.msg = "拒绝访问";
break;
case 404:
error.msg = "请求错误,未找到该资源";
break;
case 405:
error.msg = "请求方法未允许";
break;
case 408:
error.msg = "请求超时";
break;
case 500:
error.msg = "服务器端出错";
break;
case 501:
error.msg = "网络未实现";
break;
case 502:
error.msg = "网络错误";
break;
case 503:
error.msg = "服务不可用";
break;
case 504:
error.msg = "网络超时";
break;
case 505:
error.msg = "http版本不支持该请求";
break;
default:
error.msg = `连接错误${response.statusCode}`;
}
} else {
error.code = 10010;
error.msg = "连接到服务器失败";
}
return error;
};
function request(path, method, data, setting) {
const tokenInfo = uni.getStorageSync("tokenInfo");
const host = setting ? setting.host || defaultHost : defaultHost;
const token = setting ? setting.token || tokenInfo.token : tokenInfo.token;
return new Promise((resolve, reject) => {
uni.request({
url: host + path,
method: method,
data: data,
header: {
Authorization: "Bearer " + token,
},
success: (res) => {
// 状态码非200的处理
if (res.statusCode >= 400) {
const error = errorMsg(res);
uni.showToast({
title: error.msg,
icon: "none",
});
reject(errorMsg(res));
// errorCallback(errorMsg(res))
} else if (res.data.code) {
uni.showToast({
title: res.data.msg,
icon: "none",
});
// reject(errorMsg(res.data.msg))
// errorCallback(res.data)
} else {
resolve(res.data);
// successCallback(res.data)
}
},
});
});
}
export default {
get: (path, data, otherData) => {
return request(path, "get", data, otherData);
},
post: (path, data, otherData) => {
return request(path, "post", data, otherData);
},
request: request,
};
精确的错误代码识别使得开发至维护的过程更加顺滑。例如,那些新闻类的小程序,每日都涉及大量数据的交换,通过错误代码的判断,可以迅速找出数据传输过程中是否存在问题。
后续更多权限获取展望
本次任务仅涉及用户登录环节,至于获取昵称、头像乃至手机号等,则需要用户授权,这个过程较为繁琐。就好比踏入小区大门,若要进入某户人家,还需履行更多程序。若要实现这些功能,必须依照规定申请相应授权。以社交小程序为例,只有获取这些信息,才能更全面地完善用户资料,提供更精准的社交推荐。这些内容将在后续的博客文章中详细阐述,也期待着读者的关注。
在微信小程序开发过程中,登录环节是否曾让你感到棘手?不妨在评论区讲述你的经历,同时,若觉得这篇文章对你有帮助,不妨点个赞或转发一下。
用户ID:{{userInfo.id}}
用户昵称:{{userInfo.username}}
用户openId:{{userInfo.openId}}
import { ref } from "vue";
import request from "@/common/request.js";
const userInfo = ref({});
request.get("/user/info").then((res) => {
userInfo.value = res;
});
.my {
width: 100%;
}