算是个系列内容吧,最终要实现的是将uniCloud作为后端完成“扫码关注公众号后完成网站登录”
将要涉及的内容可能包括:
0.准备工作:各种配置、基础搭建
1.接受、解析、组装xml消息
2.请求access_token并缓存
3.生成带参数二维码(本节)
4.引入、封装redis缓存方法
5.引入、配置、初始化unipush
6.解析不同情况下用户扫码时推送的事件并完成登录
系列内容全部基于uniCloud+vk-uniCloud(云函数路由)+uni-app
编辑器HbuilderX最新版
云空间为阿里云
公众号为认证服务号
一、编写云函数
这个创建二维码的函数,笔者是直接放在了pub目录下/router/service/client/mp/pub/createQrCode.js
,这样不需要鉴权即可直接生成,各位担心被滥用的话,也可以加一些简单的前后端验证,这里不再赘述。
来看一下代码:
'use strict';
module.exports = {
/**
* 生成二维吗
* @url client/mp/pub/createQrCode 前端调用的url参数地址
* data 请求参数
*/
main: async (event) => {
let { data = {}, userInfo, util, filterResponse, originalParam } = event;
let { customUtil, uniID, config, pubFun, vk, db, _ } = util;
let { uid } = data;
let res = { code: 0, msg: "" };
// 业务逻辑开始-----------------------------------------------------------
let clientAppid = data.client_appid; // 客户端平台appid
let pushClientid = data.push_clientid // unipush生成的客户端推送id
let sceneCode = vk.pubfn.random(6); // 随机生成的场景值
let currentTime = new Date().getTime(); // 当前时间戳
// 判断是否有未过期的二维码(ticket)
let oldTicketInfo = await vk.baseDao.findByWhereJson({
dbName: "wx-mp-cache",
whereJson: _.and([{
name: 'qrCodeTicket'
},
{
clientAppid: clientAppid
},
{
pushClientid: pushClientid
},
{
expire_time: _.gt(currentTime)
}
])
});
if (vk.pubfn.isNotNull(oldTicketInfo)) {
res.msg = 'get old';
res.data = oldTicketInfo.ticket;
return res;
}
// 这里引用了第二节里封装的方法
let accessTokenInfo = await pubFun.getWxAccessToken();
// http请求方式: POST URL:
let url = 'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=' + accessTokenInfo.token;
let response = await uniCloud.httpProxyForEip.postJson(
url, { "expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": { "scene": { "scene_id": sceneCode } } }
)
// 还是记得要parse
response = JSON.parse(response);
// 换取二维码的ticket
let ticket = encodeURIComponent(response.body.ticket);
// 上边有请求交互,可能会浪费时间,不能直接用一开始的时间戳入库
currentTime = new Date().getTime(); // 当前时间戳
// 存入数据库
await vk.baseDao.add({
dbName: "wx-mp-cache",
dataJson: {
name: 'qrCodeTicket',
ticket: ticket,
clientAppid,
pushClientid,
expire_time: (parseInt(currentTime) + 60000)
}
});
// 缓存到redis
// 这里的方法下一节会讲到
if (vk.pubfn.isNotNull(ticket)) {
let keyName = 'qrscene_' + sceneCode; // redis的key
let redisJson = {
sceneCode,
clientAppid,
pushClientid,
expireTime: (parseInt(currentTime) + 60000)
}
// 这是一个封装好的redis方法
await pubFun.setRedisData(keyName, redisJson, 60);
}
res.msg = 'create success';
res.data = ticket; // 把ticket返回给前端
// 业务逻辑结束-----------------------------------------------------------
return res;
}
}
二、前端请求获取ticket
一般是打开登录界面,就发起请求获取tikect,当然也可以是先用手机登录之类的,然后有个切换按钮来发起请求。
// 创建并拉取公众号二维码
vk.callFunction({
url: 'client/mp/pub/createQrCode',
title: '正在生成二维码', // loading的title
data: {
client_appid: uni.getSystemInfoSync().appId, // 原生方法获取发起请求的平台appid
push_clientid: vk.vuex.get('$user.push_clientid') // 这是在app.vue初始化unipush的时候生成并缓存到vuex的
}
}).then(res => {
// 实际上拿到的是ticket,这里拼一下图片的url
this.qrCodeSrc = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' + res.data;
setTimeout(() => {
// 没登录的话60秒后提示过期
if (!vk.checkToken()) {
vk.toast('二维码已失效,点击重新获取');
}
}, 60000);
});
<view v-show="loginType == 'weixin'" class="weixin-qrcode" id="pologin">
<image class="qrCode" :src="qrCodeSrc" @click="getMpLogin">image>
view>
我这里这样弄完,就是从手机登录切换为微信登录时,发起请求拉取二维码;
然后点击二维码时,可以再次拉取(有未过期的ticket时,拉取到的是未过期的ticket)。