一、问题描述:
小程序获取手机号的代码,在 getphonenumber 回调函数里,先调用 login 拿到 code,再用 code 请求后端的接口。会有一定概率返回小程序解密失败。代码如下:
<template>
<button
open-type="getPhoneNumber"
lang="zh_CN"
@getphonenumber="onGetphonenumber">
获取手机号
</button>
</template>
<script>
import { GrantPhoneNumber } from "@/api";
export default {
methods: {
//获取手机号
onGetphonenumber(e) {
if (e.detail.errMsg.includes("ok")) {
//用户授权了手机号
wx.login({
success: res => {
let code = res.code;
GrantPhoneNumber({
code,
encryptedData: encodeURIComponent(e.detail.encryptedData),
iv: encodeURIComponent(e.detail.iv)
})
.then(res => {
console.log("GrantPhoneNumber:res :>> ", res);
})
.catch(err => {
console.log("GrantPhoneNumber:err :>> ", err);
})
}
});
}
}
}
};
</script>
二、原因:
从官方文档可以看到,在回调中使用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login
获取 code;或者在回调中先使用 checkSession 进行登录态检查
,避免 login 刷新登录态。
三、解决方法:
看了文档的描述,解决小程序解密失败有两种方式:
- 一种方法是提前拿到 code,也就是在 getphonenumber 回调之前,先调用 login 拿到 code,再用 code 请求后端的接口。
- 另一种方法是在请求后端接口的时候先判断 code 是否过期。没过期的话,去请求后端接口,否则重新获取 code。
这里我用的是第一种,通过 login 拿到的 code 的有效期,有的说是5分钟,有的说是3分钟。结合自身业务的使用场景,同时也为了以防万一,我在代码里设置了 code 的有效期是1分钟,1分钟后,如果用户没有登录的操作,则重新去获取 code,完整代码如下:
<template>
<button
class="btnClass"
open-type="getPhoneNumber"
lang="zh_CN"
@getphonenumber="onGetphonenumber"
:style="btnStyle">
获取手机号
</button>
</template>
<script>
import { GrantPhoneNumber } from "@/api";
export default {
data() {
return {
code: "", //小程序的code
isLost: false //code是否失效
};
},
onLoad() {
//防止出现解密失败,提前进行Login
wx.login({
success: res => {
console.log("phone_login:res :>> ", res);
this.code = res.code;
}
});
let interval = setInterval(() => {
if ( wx.getStorageSync("userPhone")) {
//如果用户已经登录成功 清除定时器
clearInterval(interval);
} else {
//一分钟后让code失效,重新获取
this.isLost = true;
}
}, 60000);
},
methods: {
//获取手机号
onGetphonenumber(e) {
if (e.detail.errMsg.includes("ok")) {
//用户授权了手机号
let _this = this;
if (!this.isLost) {
//code没过期 进行授权
_this.phoneHandler(e.detail.encryptedData, e.detail.iv);
} else {
//code已过期 重新拿code再授权
wx.login({
success: res => {
console.log("phoneHandler_code已过期 重新拿code :>> ", res);
this.code = res.code;
_this.phoneHandler(e.detail.encryptedData, e.detail.iv);
}
});
}
}
},
//授权手机号
phoneHandler(encryptedData, iv) {
GrantPhoneNumber({
code: this.code,
encryptedData: encodeURIComponent(encryptedData),
iv: encodeURIComponent(iv)
})
.then(res => {
console.log("GrantPhoneNumber:res :>> ", res);
// 本地缓存存一份
wx.setStorageSync("userPhone", JSON.stringify(res.phone));
})
.catch(err => {
console.log("GrantPhoneNumber:err :>> ", err);
})
}
}
};
</script>
参考资料:
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html