当前位置: 首页 > 编程日记 > 正文

小程序开发卡券

前期准备

  • 小程序内领取卡券
    1.开发者须有一个有卡券权限的公众号(服务号)和认证后的小程序账号;
    2.开发者须申请一个开放平台账号,并将小程序和公众号绑定在同一个开放平台账号下,关于开放平台的介绍请参照:微信开放平台;
    3.阅读卡券接口说明和创建卡券接口,创建卡券并获得card_id(不知道为什么微信这里只提供了接口生成卡券,明明服务号也是必备的也可以在界面上生成卡券,却没有告诉,当然自己后台调用接口生成卡片可以有更多的自定义,服务号上我个人认为是提供了几种默认的样式和配置);

具体调用

由于我其实不是很清楚后续的步骤,那么我就看到小程序提供了两个接口,添加和展示卡券的,那么我就从这俩卡券接口入手调用。

  • 接口一 :wx.addCard(Object object)

具体说明文档查看微信官方

wx.addCard({cardList: [{cardId: 'dfdsfsdfsdfsdfsdfdsfdfd',//假的cardExt: '{"code": "", "openid": "", "timestamp": "", "signature":""}'}],success(res) {console.log(res.cardList) // 卡券添加结果}})

上面代码我先调用了一下看看什么效果

可以看到,签名错误,这是因为signature参数我们没有传,那么这个参数是怎么来的呢,不得不吐槽一下微信官方,以下是官方的一句signature参数说明:

签名,商户将接口列表中的参数按照指定方式进行签名,签名方式使用 SHA1,具体签名方案参见:卡券签名

我按照链接点过去凌乱了,麻烦你请告诉我你的说明在哪儿???

获取添加卡片需要的签名signature

一通搜索之后,找到如下:

我们获取签名的流程如下:

1.使用创建卡券公众号的appid和secret获取access_token(注意是公众号的appid和secret,而不是小程序的),因为access_token每天调用次数有限每次时效2小时,请务必使用某种方法去全局保存access_token
2.使用获取到的access_token去换取ticket(这个ticket是用来参与生成签名的也是有调用次数限制和时效2小时,务必全局保存)
3.按照字典序排序以下参数 必填参数:ticket(步骤2中换取的) timestamp(当前时间戳)nonce_str(不超过32位的随机字符串) card_id(要投放的卡券的卡券id) 选填参数:code(自定义code模式下填写) openid(指定领取者的情况下填写)
4.将3.中字典序排序完成之后的参数进行字符串拼接然后使用sha1加密,即为前端需要用到的signature

签名涉及的相关变量如下

api_ticket (调用卡券相关接口的临时票据) 【必须】
timestamp (时间戳,单位为:秒)【必须】
card_id (卡卷创建后获得的卡卷ID)【必须】
code (卡券code码,相当于用户领取的那张卡卷的卡卷号)【非必须,根据业务需要】
openid (指定领取用户的opeind)【非必须,根据业务需要】
nonce_str (不超过32位随机字符串,随你随便写)【非必须,最好有】

我是在微信公众平台创建卡券的,然后code和openid并不需要用到,实际参与签名的是api_ticket、timestamp、card_id、nonce_str这4个,card_id在公众平台创建卡卷的时候就能看到,timestamp和nonce_str这两个时间戳和随机数生成就不用说了很简单,这里说一下api_ticket 。

我们首先需要获取到access_token,然后再用access_token换取api_ticket

  • 获取access_token

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

请求代码如下:

let url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxxxxxxx' + '&secret=' + 'xxxxxxxxxxxx';console.log('url',url);wx.request({url: url,data: {},method: 'GET',success(res) {console.log('信息',res)}});

点击上方蓝色标题查看官方文档,我们获取access_token的appid和secret都是服务号中的appid和secret,打印结果是:

后来又是搜,获取access_token40125错误,说服务号中其实是有两个,一个是在【基本配置】中appid和secret,另外还有一个是在【开发者工具】——【公众平台测试账号】中,我在开发过程中一开始用了基本配置中的那套,修改成后者之后验证成功获取access_token。
但是,我这次最大的坑就在这儿了,虽然这样是可以请求成功的,但是当后面签名啥的一系列都是正确的,却依然显示的签名错误,其实40125就是单纯的告诉你secrete错误,找了相关同事重新确认secrete修改才可以了

说明:
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

获取卡券的api_ticket

https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token +'&type=wx_card

通过上个步骤获取到的access_token,获取卡券签名要用到的ticket,注意type一定是wx_card,代码如下:

getTicket(access_token){let that = this;let url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' + access_token +'&type=wx_card'wx.request({url: url,data: {},method: 'GET',success(res) {console.log('ticket', res); }});},

通过以上流程,我们获取到了签名所需要的api_ticket ,服务号创建的卡券的card_id,另外一个必须的timestamp也很容易获取,获取签名前还需要对变量进行字典排序,最后是一个对这些变量拼接成的字符串进行sha1加密的算法

主流程代码如下:

let arr = [timestamp, api_ticket, cardid];
let sortarr = sort(arr);//排序
console.log('arr',arr);
let signStr = '';
for(let i=0;i<sortarr.length;i++){//拼接signStr +=sortarr[i];
}
let signature = sha1(signStr);//加密
console.log('签名',signature);

主流程中涉及的方法:

//获取timestamp时间戳
function timestampStr(){let timestamp = Date.parse(new Date());timestamp = timestamp / 1000 + ''; return timestamp;
}
//对拼接的字符串字典排序
function sort(arr){return arr.sort();
}
// 字符串加密成 hex 字符串(sha 1加密)
function sha1(s) {var data = new Uint8Array(encodeUTF8(s))var i, j, t;var l = ((data.length + 8) >>> 6 << 4) + 16, s = new Uint8Array(l << 2);s.set(new Uint8Array(data.buffer)), s = new Uint32Array(s.buffer);for (t = new DataView(s.buffer), i = 0; i < l; i++)s[i] = t.getUint32(i << 2);s[data.length >> 2] |= 0x80 << (24 - (data.length & 3) * 8);s[l - 1] = data.length << 3;var w = [], f = [function () { return m[1] & m[2] | ~m[1] & m[3]; },function () { return m[1] ^ m[2] ^ m[3]; },function () { return m[1] & m[2] | m[1] & m[3] | m[2] & m[3]; },function () { return m[1] ^ m[2] ^ m[3]; }], rol = function (n, c) { return n << c | n >>> (32 - c); },k = [1518500249, 1859775393, -1894007588, -899497514],m = [1732584193, -271733879, null, null, -1009589776];m[2] = ~m[0], m[3] = ~m[1];for (i = 0; i < s.length; i += 16) {var o = m.slice(0);for (j = 0; j < 80; j++)w[j] = j < 16 ? s[i + j] : rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1),t = rol(m[0], 5) + f[j / 20 | 0]() + m[4] + w[j] + k[j / 20 | 0] | 0,m[1] = rol(m[1], 30), m.pop(), m.unshift(t);for (j = 0; j < 5; j++)m[j] = m[j] + o[j] | 0;};t = new DataView(new Uint32Array(m).buffer);for (var i = 0; i < 5; i++)m[i] = t.getUint32(i << 2);var hex = Array.prototype.map.call(new Uint8Array(new Uint32Array(m).buffer), function (e) {return (e < 16 ? "0" : "") + e.toString(16);}).join("");return hex;
}

最后我们继续调用wx.addCard(Object object):

wx.addCard({cardList: [{cardId: 'xxxxxxx',cardExt: '{"timestamp": "' + timestamp + '", "signature":"' + signature + '"}'}],success(res) {console.log('添加结果',res.cardList) // 卡券添加结果},fail(res){console.log('添加失败',res);},complete(res){console.log('添加完成', res);}})

说明:
cardExt是一个字符串的json,里面的内容一定是参与签名的变量(不能多不能少,用了哪几个签名就填哪几个,没有用到的也不要填了)和获取到的签名signature

卡券签名错误可以在以下链接中分析排查:
卡券签名错误排查方法(官方提供)
微信卡券签名校验工具地址

参考文章:
https://www.2cto.com/kf/201801/712897.html

这里有一个后台创建卡券,前端去加载的文章:
https://blog.csdn.net/ioth5/article/details/73821768

相关文章:

php学习之道:WSDL具体解释(三)

通过声明方式定义绑定&#xff08;binding&#xff09;属性 假设你在服务中採用SOAP binding。你能够使用JAX-WS来指定一定数量的属性binding。这些属性指定相应你在WSDL中指定的属性。某些设置。比方參数类型&#xff0c;能够约束你实现的方法。这些设置也影响声明的效用。 SO…

什么是棉绒,它如何节省您的时间?

One of the biggest challenges in software development is time. It’s something we can’t easily get more of, but linting can help us make the most out of the time we have.时间是软件开发中最大的挑战之一。 这是我们无法轻易获得的更多东西&#xff0c;但是棉绒可…

可持久化线段树(主席树)【舰娘系列】【自编题】

[pixiv] https://www.pixiv.net/member_illust.php?modemedium&illust_id60083619 向大(hei)佬(e)势力学(di)习(tou) 前段时间做了一套大佬自己出的题&#xff08;大佬竟然是个宅男2333&#xff09;&#xff0c;蒟蒻的我自然是只得了30分的暴力分:-( fleet 舰队 【题目描…

读书笔记——《黑客大曝光》(1/8)

第一部分 收集情报 案例研究 Tor系统基于洋葱路由器&#xff0c;是第二代低延迟匿名系统&#xff0c;用户可通过它在互联网上进行匿名通信。Tor网络的使用者必须在他们的系统上运行一个洋葱代理&#xff0c;这个代理允许它们在Tor网络上进行通信&#xff0c;并协商一个虚拟链路…

H5 自动播放背景音频,兼容安卓和苹果手机, ios createInnerAudioContext 无法自动播放解决

原因应该是IOS不允许自动播放音频,有两种解决方法 在main.js Vue.prototype.innerAudioContext = uni.createInnerAudioContext(); //创建播放器对象 Vue.prototype.playAudio = function(audioUrl) {console.log(播放)var innerAudioContext = Vue.prototype.innerAudioCont…

粒子耗尽 粒子滤波_如何使用粒子的强大蓝牙API

粒子耗尽 粒子滤波This post is originally from www.jaredwolff.com 这篇文章最初来自www.jaredwolff.com I was defeated. 我被打败了。 I had spent the whole night trying to get a Bluetooth Low Energy project working. It was painful. It was frustrating. I was r…

Android笔记(adb命令--reboot loader)

Android 的机器通过adb进入升级模式的方法 # adb shell # reboot loader 通过上面两个命令就进入升级模式了&#xff0c;通过工具升级就好了 为什么会写这简单的一篇呢&#xff1f;因为今天干了一件很傻很傻的事&#xff0c;特别记录下来。 业务那边今天急着要把机器寄给客户&a…

样式集(八)弹窗,规则弹窗,半透明弹窗

效果图&#xff1a; 代码&#xff1a; <view class"popupBlock" v-if"showPopupBlock"><view class"xxx"><image class"xxxImg" click"showPopupBlockfalse" mode"widthFix" src"../../stat…

typeof操作符的返回值

使用typeof操作符 对一个值使用typeof操作符可能返回下列某个字符串: 1):undefined——如果这个值未定义 2):boolean——如果这个值是布尔值 3):string——如果这个值是字符串 4):number——如果这个值是数值 5):object——如果这个值是对象或null&#xff0c;数组&#xff0c;…

定制开发软件所有权_职业所有权软件开发人员指南

定制开发软件所有权介绍 (Introduction) 您的职业正在流向大海吗&#xff1f; (Is Your Career Drifting Out To Sea?) Like a frog whos slowly being boiled in a pot but doesnt realize it, 2 years into my career I slowly came to discover that I wasnt progressing a…

转:在线框架引用 bootstrap/jq/jqmobile/css框架

bootstrap百度调用 <script src"http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script><link href"http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel"stylesheet" /> 使用 Bootstrap 中文…

曲线图实现,可滚动曲线图,自定义数据

实现可以拖动的曲线图,自定义X轴数据的缩进,自定义X轴显示多少格。 效果图 数据格式,数据说明代码可见 曲线图实现 u-charts.js 可以在官网下载 <template><view class="qiun-columns"><view class=""><view class="qiu…

MongoDB 删除数据库

MongoDB 删除数据库 语法 MongoDB 删除数据库的语法格式如下&#xff1a; db.dropDatabase() 删除当前数据库&#xff0c;默认为 test&#xff0c;你可以使用 db 命令查看当前数据库名。 实例 以下实例我们删除了数据库 runoob。 首先&#xff0c;查看所有数据库&#xff1a; &…

安装meme_通过构建Meme生成器学习React

安装memeMemes are great - theyre such a fun way of describing ideas and opinions. So its no coincidence that I picked a meme generator app as the capstone project in my free React course on Scrimba. The app works by pulling a random meme image from an API …

Thunder团队第三周 - Scrum会议7

Scrum会议7 小组名称&#xff1a;Thunder 项目名称&#xff1a;i阅app Scrum Master&#xff1a;胡佑蓉 工作照片&#xff1a; 邹双黛在照相&#xff0c;所以图片中没有该同学。 参会成员&#xff1a; 王航&#xff1a;http://www.cnblogs.com/wangh013/ 李传康&#xff1a;htt…

修改u-charts的点的大小和线的粗细

效果图&#xff1a; 修改源码&#xff0c;找到u-charts.js &#xff0c; 修改他画布的点的大小&#xff0c;在这两行框的地方&#xff0c;改了就好了 完整代码&#xff1a; <template><view class"qiun-columns"><view class""><vie…

Swift中使用typealias定义一个闭包closure

在OC中我们定义一个Blocks是这样定义的&#xff1a; typedef void (^ZWProgressHUDCompletionBlock)();在Swift中定义一个闭包是这种&#xff1a; typealias ZWProgressHUDCompletionBlock()->Void转载请注明。。。欢迎大家增加交流群&#xff1a;爱疯、爱Coding&#xff1a…

react中使用构建缓存_如何在React中构建热图

react中使用构建缓存Heat maps are a great way of visualizing correlations among two data sets. With colors and gradients, it is possible to see patterns in the data almost instantly.热图是可视化两个数据集之间相关性的一种好方法。 使用颜色和渐变&#xff0c;可…

oracle rman异机恢复

Oracle源主机Oracle目标主机主机平台CentOS6.2&#xff08;final&#xff09;CentOs6.2&#xff08;FInal&#xff09;主机名 vickrmanIP地址192.168.1.11192.168.1.10实例名字orclorclOracle版本号11.2.0.411。2.0.4Oracle数据文件存储filesystemfilesystem控制文件路径/u01/a…

高阶函数-lambda表达式

#2.6 map()# 第一个参数传入一个函数&#xff0c;&#xff0c;第二个参数为一个可迭代对象li_1 (1,3,5,7)def funcA(x): return x*xm1 map(funcA,li_1)print(type(m1))print(m1())# 2.6 reduce()# 第一个参数传入一个函数&#xff0c;第二个参数 可以迭代对象 &#xff0c…

CSS动画效果无限循环放大缩小

效果图&#xff1a; CSS动画效果无限循环放大缩小 <image class"anima" mode"widthFix" click"nav" src"/static/1_btn.png"></image>.anima {animation-name: likes; // 动画名称animation-direction: alternate; // 动…

solidity 编程练习_学习Solidity编程语言并开始为区块链开发

solidity 编程练习Learn to program in Solidity in this full tutorial from Dapp University. Solidity is an object-oriented programming language for writing smart contracts. It is used for implementing smart contracts on various blockchain platforms, most not…

性能测试之二——常用的性能测试策略

性能测试的常用策略有&#xff1a; 1、基准测试 单用户测试需要打开控制台&#xff0c;获取Analysis结果&#xff08;&#xff09; 2、并发测试 多用户在同一时间做同一事情或执行同一操作&#xff0c;针对同一业务&#xff08;LR精确到毫秒&#xff09;&#xff0c;一般测试并…

KBEngine服务器环境搭建

1.概要及环境 KBEngine是一款开源服务端引擎&#xff08;中文官网http://kbengine.org/cn/&#xff09;&#xff0c;能够在Linux、Windows下部署&#xff0c;为了学习方便&#xff0c;我们在本机Windows下进行服务器环境的搭建。 1&#xff09;服务端源代码 https://github.com…

小程序判断屏幕是长屏还是短屏手机,iPhone X 类型还是 iPhone 6类型

直接看代码 globalData: {udgeBigScreen: false,//判断屏幕 }&#xff0c; onLaunch: function(e) {/**判断屏幕大小 */var judgeBigScreen () > {let result false;const res wx.getSystemInfoSync();const rate res.windowHeight / res.windowWidth;let limit res.w…

桌面应用程序 azure_如何开始使用Microsoft Azure-功能应用程序,HTTP触发器和事件队列...

桌面应用程序 azure"Serverless" architecture is all the rage in tech land at the moment, including heavy usage at my new workplace. “无服务器”架构目前在科技界风靡一时&#xff0c;包括在我的新工作场所中大量使用。 Microsoft jumped into this space …

开始Flask项目

新建Flask项目。设置调试模式。理解Flask项目主程序。使用装饰器&#xff0c;设置路径与函数之间的关系。使用Flask中render_template&#xff0c;用不同的路径&#xff0c;返回首页、登录员、注册页。用视图函数反转得到URL&#xff0c;url_for(‘login’)&#xff0c;完成导航…

JavaScript中的加法运算

<head runat"server"> <title>JavaScript实现加法计算器</title> <script type"text/javascript"> function Sum() { var txtbox1 document.getElementById("txtbox1"); var txtbox2 document.getElementById("…

计算机视觉技术 图像分类_如何训练图像分类器并教您的计算机日语

计算机视觉技术 图像分类介绍 (Introduction) Hi. Hello. こんにちは你好 你好。 こんにちは Those squiggly characters you just saw are from a language called Japanese. You’ve probably heard of it if you’ve ever watched Dragon Ball Z.您刚刚看到的那些蠕动的字符…

history对象

history对象记录了用户曾经浏览过的页面(URL)&#xff0c;并可以实现浏览器前进与后退相似导航的功能。 注意:从窗口被打开的那一刻开始记录&#xff0c;每个浏览器窗口、每个标签页乃至每个框架&#xff0c;都有自己的history对象与特定的window对象关联。 语法&#xff1a; w…