uniCloud开发公众号:三、生成带参数二维码

算是个系列内容吧,最终要实现的是将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)。

你可能感兴趣的:(unicloud,javascript,前端,开发语言)