为什么会报错?
- 没有一进入页面就获取code
- 在点击获取了用户信息 wx.getUserProfile()完成之后才去获取code,导致偶然性解密失败
- 错误信息
decodeWxUserInfo\WXBizDataCrypt.js:24
throw new Error('Illegal Buffer err')
Error: Illegal Buffer err
at WXBizDataCrypt.decryptData (***\decodeWxUserInfo\WXBizDataCrypt.js:24:11)
at Request._callback (***\getWxInfo\index.js:21:37)
at Request.self.callback (***\node_modules\request\request.js:185:22)
at Request.emit (node:events:390:28)
at Request.<anonymous> (***\request\request.js:1154:10)
at Request.emit (node:events:390:28)
at IncomingMessage.<anonymous> (***\node_modules\request\request.js:1076:12)
at Object.onceWrapper (node:events:509:28)
at IncomingMessage.emit (node:events:402:35)
at endReadableNT (node:internal/streams/readable:1343:12)
错误示例
<view class="login-page-btn" wx:if="{{!hasUserInfo}}">
<van-button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile" type="info" size="large" round>登录</van-button>
</view>
data: {
canIUseGetUserProfile: false,
},
onLoad(options) {
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log('userInfo', res);
this.login(res)
},
fail: _ => {
wx.showToast({
title: '用户信息获取失败',
icon: "error",
duration: 1000 * 2
})
}
})
},
login(event) {
wx.showLoading({
title: '登陆中~',
})
const iv = event.iv;
const encryptedData = event.encryptedData;
this.getCode(iv, encryptedData)
},
getCode(iv, encryptedData) {
// 登录
wx.login({
success: res => {
wx.$http.post('getUserInfo', {
code: res.code,
iv,
encryptedData
}).then(res => {
this.getUserInfo(res)
}).catch(_ => {
wx.hideLoading()
wx.showToast({
title: '获取code失败,请重新登录',
icon: "none",
duration: 1000 * 3
})
})
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
},
getUserInfo(res) {
console.log('iv, encryptedData', res);
wx.hideLoading()
wx.showToast({
title: res.msg,
icon: "success",
duration: 1000 * 1.5
})
},
-
这样操作的结果:
-
起初正常
-
过一段时间再次点击会报node解密失败
-
-
这样的问题出现在
wx.login
需要在执行wx.getUserProfile()
之前拿到,具体原因未明
正确示例
- 进入页面拿到code,存起来
- 点击获取个人信息按钮,成功之后调用this.login()
- 然后拿到code,iv,encryptedData发送给后端。
- node通过code去换到openid,session_key,
- node再通过session_key,iv,encryptedData去拿到加密后的用户信息进行解密
- 如果code过期了直接返回
- 否则进行解密,解密之后返回给前端
data: {
canIUseGetUserProfile: false,
},
onLoad(options) {
this.getCode();
if (wx.getUserProfile) {
this.setData({
canIUseGetUserProfile: true
})
}
},
getCode() {
// 登录
wx.login({
success: res => {
this.setData({
code: res.code
})
}
})
},
getUserProfile(e) {
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
wx.getUserProfile({
desc: '用于完善会员资料', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
success: (res) => {
console.log('userInfo', res);
this.login(res)
},
fail: _ => {
wx.showToast({
title: '用户信息获取失败',
icon: "error",
duration: 1000 * 2
})
}
})
},
login(event) {
wx.showLoading({
title: '登陆中~',
})
const iv = event.iv;
const encryptedData = event.encryptedData;
wx.$http.post('getUserInfo', {
code: this.data.code,
iv,
encryptedData
}).then(res => {
this.getUserInfo(res)
}).catch(err => {
wx.hideLoading()
console.log(err);
wx.showToast({
title: err,
icon: "none",
duration: 1000 * 3
})
})
},
getUserInfo(res) {
console.log('iv, encryptedData', res);
wx.hideLoading()
if (res.code === 40163) {
wx.showToast({
title: 'code过期,请重新登录!',
icon: "none",
duration: 1000 * 1.5
})
this.getCode() // 重新获取一次后,再次点击的时候可以用最新的code
} else {
wx.showToast({
title: res.msg,
icon: "success",
duration: 1000 * 1.5
})
}
},
- index.js
import {getUserInfo } from './getWxInfo' const express = require('express'); const router = express.Router(); router.post('/getUserInfo', (req, res) => { const params = req.body; getWxInfo.getUserInfo(params.code, params.iv, params.encryptedData).then(child => { console.log('child', child); res.send({ code: 200, msg: '登录成功', body: child }); }).catch(err => { res.send({ code: err.errcode, msg: err.errmsg, body: null }) console.log({ err }); }) });
- getWxInfo/index.js
const request = require('request') const WXBizDataCrypt = require('../decodeWxUserInfo/WXBizDataCrypt') const APP_URL = 'https://api.weixin.qq.com/sns/jscode2session' const APP_ID = 'wx276*********2' //自己小程序的app id ,在公众开发者后台可以看到 const APP_SECRET = 'd37**************104' //自己小程序的app secrect,在公众开发者后台可以看到 exports.getUserInfo = async (code, iv, encryptedData) => { // let code=code //解析前端传递过来的参数js_code return new Promise((resolve, reject) => { request(`${APP_URL}?appid=${APP_ID}&secret=${APP_SECRET}&js_code=${code}&grant_type=authorization_code`, function (err, response, body) { if (!err && response.statusCode == 200) { let JSONBody = JSON.parse(body) if (!JSONBody.errcode) { let session_key = JSONBody.session_key const pc = new WXBizDataCrypt(APP_ID, session_key) const data = pc.decryptData(encryptedData, iv) resolve(data) } else { reject(JSONBody) } } else { console.log('errs'); reject(err) } }) }) }