2018-08-31 23:15:39 Sukla 阅读数 195
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27754 人正在学习 去看看 秦子恒

1.微信开发者工具,扫描登陆

2.申请Appid

3.添加项目

4.编码调试Wxml、Wxss

5.又叫微信应用号,wxml+wxss+js+配置,安装到微信端

6.wxml遵循严格的XML语法

7.wxss使用rps单位响应式像素,样式导入 

@import '*.wxss'

不需要less sass等

8.微信小程序中的js中没有BOM模块、没有DOM模块、有ECMAScript模块、实现了wx全局对象类似浏览器中的window对象

9.配置项非常严格的json格式,没有注释,使用双引号,不用单引号

10.微信小程序使用rpx作为单位,规定屏幕宽度是750rpx,是一个响应式的单位,在iPhone6上屏幕像素比是2,则在wxss屏幕宽度最大宽度就是375rpx

11.在微信小程序中不要将字体单位设置成rpx,还是要使用px,否则的话字会十分小,看不清

12.布局一般是一个头部通栏的nav,然后是一个九宫格布局,使用flex能方便地实现

13.将view标签kan看作div,将text标签看作span,将navigator标签看作a标签

14..............

2018-03-11 18:59:25 helloworldfor 阅读数 159
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27754 人正在学习 去看看 秦子恒

感谢Worktile的投稿,他的博客:http://www.jianshu.com/u/82213c618353a现如今,微信已经不再只承担着交流沟通、娱乐大众的功能,微信公众号的推出将微信逐渐转变成个人、商家、企业单位用来营销的重要工具。而微信推出的公众号开发功能,为我们码农带来很大的方便,让我们创造出更多的可能性。今天,就结合自己的些许经验,跟大家分享下有关公众号开发的操作。而对于大部分的开发者来说可能已经很熟悉微信公众号开发,所以这篇入门篇适用于初始了解和做公众号开发的同学。Tips:本文根据微信官方文档的内容编写,并会附上实例代码(nodejs)。

第一章:开始开发(准备阶段)--------------1. 接入指南接入微信公众平台开发,开发者需要按照如下步骤完成:·填写服务器配置说明:URL是开发者用来接收微信消息和事件的接口URL,该接口尽量写成两个请求方式,1:get请求,用于验证如下地址有效性,2:post请求, 用于接收消息和事件,Token 可以随便定义用于验证接口签名有效性, EncodingAESKey是加密的密钥,下面加密方式选兼容模式或者安全模式的时候开发者可根据该密钥对数据进行加解密·验证如上URL服务器地址的有效性根据官方文档的说明,微信验证接口会带下面几个参数#插播福利我把互联网领悟的经典技术书和资源整理了一下,涵盖34个领悟,143家公司的面试真题,以及常见互联网技术领悟经典书和面试书和知名互联网公司校招薪资汇总表,领取方式:关注此号,回复:干货,加入技术群,回复“入群”下载地址:http://www.jianshu.com/p/4a9599a230af)服务端接口接收到这些参数后进行签名验证,如下代码:exports.check = function (req, res, next) {// 在这里验证签名var signature = req.query['signature'],timestamp = req.query['timestamp'],nonce = req.query['nonce'],echostr = req.query['echostr'];var sha1 = crypto.createHash('sha1'),sha1Str = sha1.update([config.weixin.token, timestamp, nonce].sort().join('')).digest('hex');res.writeHead(200, {'Content-Type': 'text/plain'});res.end((sha1Str === signature) ? echostr : '');return res;};·依据接口文档实现业务逻辑这里就是根据业务需求,进行接口调用的编程了,下面我会一一介绍2. 获取access_tokenaccess_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。该接口一天只能请求2000次,开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。如下代码事例:exports.get_token = function (fn) {redis.get(weixin_token, function (err, token_str) {if (token_str) {return fn(err, JSON.parse(token_str));} else {request.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + app_id + "&secret=" + app_secret, function (err, response, body) {if (JSON.parse(body).errcode == 45009) {return fn(err)} else {redis.set(weixin_token, body, function (err) {redis.expire(weixin_token, 7000, function () {return fn(err, JSON.parse(body));};上面的事例代码中,首先我会从redis中获取到access_token,因为我最初获取access_token的时候写入到redis中了,官方给的有效时间是7200秒,我放在redis中的有效时间是7000秒,所以我这里的token不会过期,过期后会重新调用接口获取并写入redis第二章:自定义菜单实例代码中只写入创建接口的调用,查询和删除就不举例了。·自定义菜单创建接口如下代码事例以及说明:get_token(function(err, obj){var access_token = obj.access_token;request.post({url: "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + access_token,json: {"button":[{"type":"view","name":"工作台","url":"http://worktile.com"},{"name":"解决方案","sub_button": [{"type":"view","name":"研发","url":"https://pro.worktile.com/solution/dev"}{"type":"view","name":"最佳实践","url":"https://worktile.com/can"}{"name":"更多","sub_button":[{"type":"view","name":"下载应用","url":"http://a.app.qq.com/o/simple.jsp?pkgname=com.worktile"},{"type":"click","name":"合作","key":"work_together"}]}, function(err, res, body){console.log(body)})这里get_token方法就是上面第一章中#获取access_token ,而且我这里是作为脚本执行的,这样方便以后随便修改自定义菜单内容·自定义菜单查询接口http请求方式:GEThttps://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN·自定义菜单删除接口http请求方式:GEThttps://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN第三章:消息管理·接收消息接收的消息分为普通消息和事件消息,统一有第一章中接入指南填写的RUL接口来接收处理exports.receive = function (req, res, next) {// 在这接收消息var xml = '';req.setEncoding('utf8');req.on('data', function (chunk) {xml += chunk;});req.on('end', function () {toJSON(xml, res);});};说明:receive方法就是接收用户发给公众号的消息,内容格式是xml,toJSON就是我解析xml为json的方法,如下//解析器var toJSON = function (xml, res) {var msg = {};xml2js.parseString(xml, function (err, result) {var data = result.xml;msg.ToUserName = data.ToUserName[0];msg.FromUserName = data.FromUserName[0];msg.CreateTime = data.CreateTime[0];msg.MsgType = data.MsgType[0];switch (msg.MsgType) {case 'text' :msg.Content = data.Content[0];msg.MsgId = data.MsgId[0];res.setHeader("Content-Type", "text/plain");res.send("");return handle_text(msg, res);break;case 'image' :msg.PicUrl = data.PicUrl[0];msg.MsgId = data.MsgId[0];msg.MediaId = data.MediaId[0];res.setHeader("Content-Type", "text/plain");res.send("");break;case 'voice' :msg.MediaId = data.MediaId[0];msg.Format = data.Format[0];msg.MsgId = data.MsgId[0];res.setHeader("Content-Type", "text/plain");res.send("");break;case 'video' :msg.MediaId = data.MediaId[0];msg.ThumbMediaId = data.ThumbMediaId[0];msg.MsgId = data.MsgId[0];res.setHeader("Content-Type", "text/plain");res.send("");break;case 'location' :msg.Location_X = data.Location_X[0];msg.Location_Y = data.Location_Y[0];msg.Scale = data.Scale[0];msg.Label = data.Label[0];msg.MsgId = data.MsgId[0];res.setHeader("Content-Type", "text/plain");res.send("");break;case 'link' :msg.Title = data.Title[0];msg.Description = data.Description[0];msg.Url = data.Url[0];msg.MsgId = data.MsgId[0];res.setHeader("Content-Type", "text/plain");res.send("");break;case 'event' :msg.Event = data.Event[0];if (data.EventKey && _.isArray(data.EventKey) && data.EventKey.length > 0) {msg.EventKey = data.EventKey[0];return handle_event(msg, res);}res.setHeader("Content-Type", "text/plain");res.send("");break;}});};说明:这里我用户发过来的消息xml解释称json数据msg, 根据不同的类型做不同的处理,如上文本,图片,音频,视频,链接,事件等消息var handle_text = function (msg, res) {var text = msg.Content;if(text.trim() == "研发"){var data = {"touser":msg.FromUserName,"msgtype":"news","news":{"articles": [{"title":"重磅!Worktile 推出研发管理解决方案","description":"项目进度清晰掌握,快速跟进产品Bug,多维度统计报表,文件文档有序管理","url":"https://pro.worktile.com/solution/dev","picurl":"https://wt-prj.oss.aliyuncs.com/b327e3a5666048279583e8e026ac6b87/4bb6e53c-8516-4466-b278-4f3b596e46db.png"sendMessageToUser(data);}else if(text.trim() == "电商"){var data = {"touser":msg.FromUserName,"msgtype":"news","news":{"articles": [{"title":"Worktile 『电商解决方案』上线!","description":"降低运营成本,提高团队效率。日常运营、大促筹备、售后跟踪、研发管理……尽在掌握。","url":"https://pro.worktile.com/solution/ecommerce","picurl":"https://cdn.worktile.com/solution/ecommerce.png"sendMessageToUser(data);说明:这是对文本消息的处理,如上,如果接收到 研发 字样的消息,公众号会给该用户发送一条新闻消息var handle_event = function (msg, res) {console.log("weixin receive message ===", msg)if (msg.Event == 'CLICK' && msg.EventKey == 'work_together') {var text = "Hello,谢谢对 Worktile 的关注啦,请访问worktile官方网站了解。。。。。";var data = {touser : msg.FromUserName,msgtype: "text",text : {content: textsendMessageToUser(data);说明:这是对事件消息的处理,如上,如果接收到 msg.Event == 'CLICK' && msg.EventKey == 'work_together' 事件的消息,公众号会给该用户发送一条文本消息,当然事件消息有很多,如:subscribe关注公众号消息,unsubscribe取消关注,扫描带参数二维码事件,还有如上说的自定义菜单事件, 上报地理位置事件等var sendMessageToUser = function ( data) {get_token(function (err, obj) {request.post({url : "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + obj.access_token,headers: {"Content-Type": "application/json"},json : data}, function (err, res, body) {console.log("sendmessage....", body)这个发放就是调用微信接口给用户发送消息,那接下来咱们就看下发送消息#插播福利我把互联网领悟的经典技术书和资源整理了一下,涵盖34个领悟,143家公司的面试真题,以及常见互联网技术领悟经典书和面试书和知名互联网公司校招薪资汇总表,领取方式:关注此号,回复:干货,加入技术群,回复“入群”下载地址:http://www.jianshu.com/p/4a9599a230af)发送消息发送消息分为,发送被动消息,发送客服消息,发送模版消息1.被动消息如上接收消息后根据消息判断发送给用户的消息即是被动消息2.客服消息,是公众号收到用户来的消息客服根据内容回复给用户的消息如果用户并没有给公众号发消息,此时客服是无法给用户发送消息的,这是微信做的一个限制如下代码:wtutil.get_token(function (err, obj) {//var text = "你好,这是一条消息,多谢支持...";//var data = {// touser : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI",// msgtype: "text",// text : {// content: text// }//};var data = {touser : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI",msgtype: "image","image":{"media_id":"ZqQGrsR6ivb273zLApNfkEdAP3UI8nHJTJ9ekelfJ8OhKUF6UG-o6YbOBv4uWf4R"}};request.post({url : "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + obj.access_token,headers: {"Content-Type": "application/json"},json : data}, function (err, res, body) {console.log(body);})});msgtype: 是消息类型,上面注释掉的是文本消息,下面是个图片消息,touser是用户的openid,这里我只是取过来直接使用的,这里跟上面接收消息后处理给用户发消息有写重复,就不多介绍了3.模版消息大家肯定很熟悉,比如Worktile的微信公众号接收任务消息通知,这样的消息就是模版消息模版消息相对来说复杂一下,首先要从公众号添加或者申请消息模版,如下图那么有了消息模版之后就可以拿到模版ID,然后给用户发送模版消息了get_token(function (err, obj) {var data = {"touser" : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI","template_id": "z6yV_lOIAM-LQbsrG-B3hTQvwt8_4Y3wVU2PH9UW16c","url" : "https://worktile.com","topcolor" : "#FF00FF","data" : {"first" : {"value": "测试哈哈哈,颜色可以自定义","color": "#33FF00"},"one": {"value": "one","color": "#173177"},"two": {"value": "two","color": "#FF0033"},"three": {"value": "three","color": "#173177"},"remark" : {"value": "remark,了解更多详情,关注我。。。。","color": "#33FF00"request.post({url : "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + obj.access_token,headers: {"Content-Type": "application/json"},json : data}, function (err, res, body) {console.log(body, "----")})});需要说明的是参数中data里面的key(first, one, two,three, remark)是模版中定义的,这里需要根据模版内容来写,还有可以设置每个字段的颜色值等属性到此消息管理这部分已经说的差不多了,咱们继续介绍。。。第四章:微信网页开发这个章节跟前面几章不同,前面几章介绍的是公众号开发的一些东西,这个章节介绍的是网页开发,主要针对h5应用或者是页面的开发,Worktile微信版就是微信网页开发完成的,下面咱们一步步的介绍。·微信网页授权微信网页授权采用的是Oauth2.0的授权方式:第一步:访问如下链接获取codehttps://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirectredirect_uri是你h5地址,授权成功后会把code加入到地址上,类似于:https://weixin.worktile.com?code=xxx这样第二步:通过code换取网页授权access_token请求接口(get请求)https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code返回的结果如下{ "access_token":"ACCESS_TOKEN","expires_in":7200,"refresh_token":"REFRESH_TOKEN","openid":"OPENID","scope":"SCOPE" }access_token是用户授权的token,openid是用户对于该公众号的唯一标示,refresh_token:可以调用刷新token的接口获取最新的token第三步:获取用户信息(需scope为 snsapi_userinfo)请求接口(get请求)https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN通过以上3个步骤就可以获取用户的信息,进行用户的管理操作了·微信JS-SDK网页开发中,有时候我们会自定义分享的内容,图片,音频,视频的上传,下载,地理位置,摇一摇周边,扫码,支付等的功能,这时候就需要js-sdk的开发了,下面简单介绍下js-sdk的使用,读者还可以查看官方开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN·绑定域名先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。·引入JS文件在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js如需使用摇一摇周边功能,请引入http://res.wx.qq.com/open/js/jweixin-1.1.0.js·通过config接口注入权限验证配置如下代码需要在网页中配置wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: '', // 必填,公众号的唯一标识timestamp: , // 必填,生成签名的时间戳nonceStr: '', // 必填,生成签名的随机串signature: '',// 必填,签名,见附录1jsApiList: [] // 必填,需要使用的JS接口列表});`如上代码中的timestamp, nonceStr, signature需要服务端做好签名返回给页面,这里可以使用异步调用的方式,如下为服务端签名代码`var sign = function (jsapi_ticket, url) {var ret = {jsapi_ticket: jsapi_ticket,nonceStr: createNonceStr(),timestamp: createTimestamp(),url: url};var string = raw(ret);jsSHA = require('jssha');shaObj = new jsSHA(string, 'TEXT');ret.signature = shaObj.getHash('SHA-1', 'HEX');return ret;};ret就是我们需要的签名结果,其中jsapi_ticket是调用ticket接口获取的,官方文档中也有说明https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token= access_token&type=jsapi, rul是获取签名的当前网页地址, nonceStr:随机字符串,timestamp:当前10位时间戳var raw = function (args) {var keys = Object.keys(args);keys = keys.sort()var newArgs = {};keys.forEach(function (key) {newArgs[key.toLowerCase()] = args[key];});var string = '';for (var k in newArgs) {string += '&' + k + '=' + newArgs[k];}string = string.substr(1);return string;};这个方法是对签名对象的一个字符串格式化算法·通过ready接口处理成功验证wx.ready(function(){// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。});·调用接口根据config里面 jsApiList的配置可以调用js-sdk的接口,如分享朋友圈,分享微信好友等。。。wx.onMenuShareTimeline({title: '', // 分享标题link: '', // 分享链接imgUrl: '', // 分享图标success: function () {// 用户确认分享后执行的回调函数},cancel: function () {// 用户取消分享后执行的回调函数}});这是一个分享到朋友圈的接口,可以自定义标题,自定义链接,自定义图标如果想调用更多的js-sdk的接口可以参考官方文档进行开发:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN·微信网页开发样式库https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784134&token=&lang=zh_CN·微信web开发者工具https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_CN以上就是微信公众号开发的一些内容,算是入门篇。其实关于微信的开发还有很多可以做的事情,而且随着需求越来越多,技术越来越完善,相信之后关于微信的开发一定还会有更多惊喜!

2017-01-18 22:48:53 susan_shuna 阅读数 2433
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27754 人正在学习 去看看 秦子恒

微信小程序开发中遇到的问题总结

(1) 分隔线高度使用rpx问题
在相邻的两条信息直接都会有一个分割线,将线的高度都设置成1rpx,在第一条和第二条之前的分隔线没有显示,但是其他的都展示了,分割线的属性是一样的,而且在不同的手机上(分辨率不同)不显示的分割线也是不同的,有的分辨率好几条分割线都不显示,不知道这是模拟器的bug还是rpx的bug。解决方法:分割线的高度尺寸单位使用了px,解决了这个问题。

(2) Page注册问题
这个错误可能很容易理解,页面注册错误。页面是通过Page对象来渲染的,每个页面对应的js文件必须要创建page,最简单的方式就是在js文件下写入Page({}),在page中有管理页面渲染的生命周期,以及数据处理,事件都在这完成。这个错误引起的原因一般都是刚创建页面,js文件还有有处理或者忘了处理。
解决方法:养成创建页面的同时在js文件先创建Page的习惯.

(3) Page route 错误
重复调用路由引起的,处理方法就是删除一个路由,删除组件或者删除wx.navigateTo。

(4) Don’t have * Handle in current page.
其实这种问题出现一般就是我们在wxml定义了一些处理事件,但是在js文件中没有实现这个时事件的处理方法,就会出现这个错误。那么我们按提示在js文件加上事件处理
解决方法:不要漏掉任何调用事件的方法实现

(5) tabBar 设置不显示
对于tabBar不显示,原因有很多,查找这个错误直接去app.json这个文件

未将页面注册到app.json中
tabBar写法错误导致的不显示,将其中的大写字母B写成小写,导致tabBar不显示
tabBar的list中没有写pagePath字段,或者pagePath中的页面没有注册
tabBar的list的pagePath指定的页面没有写在注册页面第一个。微信小程序的逻辑是”pages”中的第一个页面是首页,也就是程序启动后第一个显示的页面,如果tabBar的list的pagePath指定的页面都不是pages的第一个,当然也就不会显示tabBar了。
tabBar的数量低于两项或者高于五项,微信官方中明确规定tabBar的至少两项最多五项。超过或者少于都不会显示tabBar。

(6) wx.navigateTo 无法打开页面
一个应用同时只能打开5个页面,当已经打开了5个页面之后,wx.navigateTo不能正常打开新页面。请避免多层级的交互方式,或者使用wx.redirectTo

(7) 本地资源无法通过css获取
background-image:可以使用网络图片,或者 base64,或者使用标签

(8)wx.navigateTo api是无法跳转到tabBar的地址连接, 解决方案是wx.switchTab, 但是又有一个问题这里api是不能传参数的,要注意的是wx.switchTab的地址是以”/”开头

2016-11-25 16:33:29 u013695026 阅读数 493
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27754 人正在学习 去看看 秦子恒

本篇技术博客来自Worktile 微信之父 @龚林杰的动情分享,为您详细讲述我们微信公众号【getworktile】背后的点点滴滴~

现如今,微信已经不再只承担着交流沟通、娱乐大众的功能,微信公众号的推出将微信逐渐转变成个人、商家、企业单位用来营销的重要工具。而微信推出的公众号开发功能,为我们码农带来很大的方便,让我们创造出更多的可能性。

今天,就结合自己的些许经验,跟大家分享下有关公众号开发的操作。而对于大部分的开发者来说可能已经很熟悉微信公众号开发,所以这篇入门篇适用于初始了解和做公众号开发的同学。

Tips:本文根据微信官方文档的内容编写,并会附上实例代码(nodejs)。

第一章:开始开发(准备阶段)

1. 接入指南

接入微信公众平台开发,开发者需要按照如下步骤完成:

  • 填写服务器配置

替代文字
说明:URL是开发者用来接收微信消息和事件的接口URL,该接口尽量写成两个请求方式,1:get请求,用于验证如下地址有效性,2:post请求, 用于接收消息和事件,Token 可以随便定义用于验证接口签名有效性, EncodingAESKey是加密的密钥,下面加密方式选兼容模式或者安全模式的时候开发者可根据该密钥对数据进行加解密

  • 验证如上URL服务器地址的有效性

    根据官方文档的说明,微信验证接口会带下面几个参数

参数 描述
signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
timestamp 时间戳
nonce 随机数
echostr 随机字符串

服务端接口接收到这些参数后进行签名验证,如下代码:

exports.check = function (req, res, next) {
         // 在这里验证签名
         var signature = req.query['signature'],
               timestamp = req.query['timestamp'],
               nonce = req.query['nonce'],
               echostr = req.query['echostr'];
          var sha1 = crypto.createHash('sha1'),
                sha1Str = sha1.update([config.weixin.token, timestamp, nonce].sort().join('')).digest('hex');
                res.writeHead(200, {'Content-Type': 'text/plain'});
               res.end((sha1Str === signature) ? echostr : '');
               return res;
};
  • 依据接口文档实现业务逻辑

    这里就是根据业务需求,进行接口调用的编程了,下面我会一一介绍

2. 获取access_token

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

如下代码事例:

exports.get_token = function (fn) {
        redis.get(weixin_token, function (err, token_str) {
            if (token_str) {
                return fn(err, JSON.parse(token_str));
            } else {
                request.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + app_id + "&secret=" + app_secret, function (err, response, body) {
                    if (JSON.parse(body).errcode == 45009) {
                        return fn(err)
                    } else {
                        redis.set(weixin_token, body, function (err) {
                            redis.expire(weixin_token, 7000, function () {
                                return fn(err, JSON.parse(body));
                            });
                        });
                    }
                });
            }
        });
    };

上面的事例代码中,首先我会从redis中获取到access_token,因为我最初获取access_token的时候写入到redis中了,官方给的有效时间是7200秒,我放在redis中的有效时间是7000秒,所以我这里的token不会过期,过期后会重新调用接口获取并写入redis

第二章:自定义菜单

实例代码中只写入创建接口的调用,查询和删除就不举例了。

  • 自定义菜单创建接口
    如下代码事例以及说明:
   get_token(function(err, obj){
        var access_token = obj.access_token;
        request.post({
            url: "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + access_token,
            json:  {
                "button":[
                    {
                        "type":"view",
                        "name":"工作台",
                        "url":"http://worktile.com"
                    },
                    {
                        "name":"解决方案",
                        "sub_button": [
                          {
                            "type":"view",
                            "name":"研发",
                            "url":"https://pro.worktile.com/solution/dev"
                          }
                          {
                            "type":"view",
                            "name":"最佳实践",
                            "url":"https://worktile.com/can"
                          }
                        ]
                    },
                    {
                        "name":"更多",
                        "sub_button":[
                            {
                                "type":"view",
                                "name":"下载应用",
                                "url":"http://a.app.qq.com/o/simple.jsp?pkgname=com.worktile"
                            },
                            {
                                "type":"click",
                                "name":"合作",
                                "key":"work_together"
                            }]
                    }]
            }
        }, function(err, res, body){
            console.log(body)
        })
    });

这里get_token方法就是上面第一章中#获取access_token ,而且我这里是作为脚本执行的,这样方便以后随便修改自定义菜单内容

第三章:消息管理

  • 接收消息
    接收的消息分为普通消息和事件消息,统一有第一章中 接入指南 填写的RUL接口来接收处理
exports.receive = function (req, res, next) {
        // 在这接收消息
        var xml = '';
        req.setEncoding('utf8');
        req.on('data', function (chunk) {
            xml += chunk;
        });
        req.on('end', function () {
            toJSON(xml, res);
        });
    };

说明:receive方法就是接收用户发给公众号的消息,内容格式是xml,toJSON就是我解析xml为json的方法,如下

 //解析器
    var toJSON = function (xml, res) {
        var msg = {};
        xml2js.parseString(xml, function (err, result) {
            var data = result.xml;
            msg.ToUserName = data.ToUserName[0];
            msg.FromUserName = data.FromUserName[0];
            msg.CreateTime = data.CreateTime[0];
            msg.MsgType = data.MsgType[0];
            switch (msg.MsgType) {
                case 'text' :
                    msg.Content = data.Content[0];
                    msg.MsgId = data.MsgId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    return handle_text(msg, res);
                    break;
                case 'image' :
                    msg.PicUrl = data.PicUrl[0];
                    msg.MsgId = data.MsgId[0];
                    msg.MediaId = data.MediaId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
                case 'voice' :
                    msg.MediaId = data.MediaId[0];
                    msg.Format = data.Format[0];
                    msg.MsgId = data.MsgId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
                case 'video' :
                    msg.MediaId = data.MediaId[0];
                    msg.ThumbMediaId = data.ThumbMediaId[0];
                    msg.MsgId = data.MsgId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
                case 'location' :
                    msg.Location_X = data.Location_X[0];
                    msg.Location_Y = data.Location_Y[0];
                    msg.Scale = data.Scale[0];
                    msg.Label = data.Label[0];
                    msg.MsgId = data.MsgId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
                case 'link' :
                    msg.Title = data.Title[0];
                    msg.Description = data.Description[0];
                    msg.Url = data.Url[0];
                    msg.MsgId = data.MsgId[0];
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
                case 'event' :
                    msg.Event = data.Event[0];
                    if (data.EventKey && _.isArray(data.EventKey) && data.EventKey.length > 0) {
                        msg.EventKey = data.EventKey[0];
                        return handle_event(msg, res);
                    }
                    res.setHeader("Content-Type", "text/plain");
                    res.send("");
                    break;
            }
        });
    };

说明:这里我用户发过来的消息xml解释称json数据msg, 根据不同的类型做不同的处理,如上文本,图片,音频,视频,链接,事件等消息

var handle_text = function (msg, res) {
        var text = msg.Content;
        if(text.trim() == "研发"){
            var data = {
                "touser":msg.FromUserName,
                "msgtype":"news",
                "news":{
                    "articles": [
                        {
                            "title":"重磅!Worktile 推出研发管理解决方案",
                            "description":"项目进度清晰掌握,快速跟进产品Bug,多维度统计报表,文件文档有序管理",
                            "url":"https://pro.worktile.com/solution/dev",
                            "picurl":"https://wt-prj.oss.aliyuncs.com/b327e3a5666048279583e8e026ac6b87/4bb6e53c-8516-4466-b278-4f3b596e46db.png"
                        }
                    ]
                }
            };
            sendMessageToUser(data);
        }else if(text.trim() == "电商"){
            var data = {
                "touser":msg.FromUserName,
                "msgtype":"news",
                "news":{
                    "articles": [
                        {
                            "title":"Worktile 『电商解决方案』上线!",
                            "description":"降低运营成本,提高团队效率。日常运营、大促筹备、售后跟踪、研发管理……尽在掌握。",
                            "url":"https://pro.worktile.com/solution/ecommerce",
                            "picurl":"https://cdn.worktile.com/solution/ecommerce.png"
                        }
                    ]
                }
            };
            sendMessageToUser(data);
        }
    };

说明:这是对文本消息的处理,如上,如果接收到 研发 字样的消息,公众号会给该用户发送一条新闻消息

    var handle_event = function (msg, res) {
        console.log("weixin receive message ===", msg)
        if (msg.Event == 'CLICK' && msg.EventKey == 'work_together') {
            var text = "Hello,谢谢对 Worktile 的关注啦,请访问worktile官方网站了解。。。。。";
            var data = {
                touser : msg.FromUserName,
                msgtype: "text",
                text   : {
                    content: text
                }
            };
            sendMessageToUser(data);
        }
    };

说明:这是对事件消息的处理,如上,如果接收到 msg.Event == 'CLICK' && msg.EventKey == 'work_together' 事件的消息,公众号会给该用户发送一条文本消息,当然事件消息有很多,如:subscribe关注公众号消息,unsubscribe取消关注,扫描带参数二维码事件,还有如上说的自定义菜单事件, 上报地理位置事件等

    var sendMessageToUser = function ( data) {
        get_token(function (err, obj) {
            request.post({
                url    : "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + obj.access_token,
                headers: {"Content-Type": "application/json"},
                json   : data
            }, function (err, res, body) {
                console.log("sendmessage....", body)
            })
        });
    };

这个发放就是调用微信接口给用户发送消息,那接下来咱们就看下发送消息

  • 发送消息
    发送消息分为,发送被动消息,发送客服消息,发送模版消息

    1. 被动消息如上接收消息后根据消息判断发送给用户的消息即是被动消息
    2. 客服消息,是公众号收到用户来的消息客服根据内容回复给用户的消息
      如果用户并没有给公众号发消息,此时客服是无法给用户发送消息的,这是微信做的一个限制
      如下代码:
wtutil.get_token(function (err, obj) {
        //var text = "你好,这是一条消息,多谢支持...";
        //var data = {
        //    touser : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI",
        //    msgtype: "text",
        //    text   : {
        //        content: text
        //    }
        //};
        var data = {
            touser : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI",
            msgtype: "image",
            "image":
            {
                "media_id":"ZqQGrsR6ivb273zLApNfkEdAP3UI8nHJTJ9ekelfJ8OhKUF6UG-o6YbOBv4uWf4R"
            }
        };
        request.post({
            url    : "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + obj.access_token,
            headers: {"Content-Type": "application/json"},
            json   : data
        }, function (err, res, body) {
            console.log(body);
        })
    });

msgtype: 是消息类型,上面注释掉的是文本消息,下面是个图片消息,touser是用户的openid,这里我只是取过来直接使用的,这里跟上面接收消息后处理给用户发消息有写重复,就不多介绍了

3.模版消息大家肯定很熟悉,比如Worktile的微信公众号接收任务消息通知,这样的消息就是模版消息

Screenshot_2016-11-08-16-34-52.png

模版消息相对来说复杂一下,首先要从公众号添加或者申请消息模版,如下图
替代文字
那么有了消息模版之后就可以拿到模版ID,然后给用户发送模版消息了

    get_token(function (err, obj) {
        var data = {
            "touser"     : "oy4hbwbd0MOMmn8aUtQWMcNxs8PI",
            "template_id": "z6yV_lOIAM-LQbsrG-B3hTQvwt8_4Y3wVU2PH9UW16c",
            "url"        : "https://worktile.com",
            "topcolor"   : "#FF00FF",
            "data"       : {
                "first"   : {
                    "value": "测试哈哈哈,颜色可以自定义",
                    "color": "#33FF00"
                },
                "one": {
                    "value": "one",
                    "color": "#173177"
                },
                "two": {
                    "value": "two",
                    "color": "#FF0033"
                },
                "three": {
                    "value": "three",
                    "color": "#173177"
                },
                "remark"  : {
                    "value": "remark,了解更多详情,关注我。。。。",
                    "color": "#33FF00"
                }
            }
        };
        request.post({
            url    : "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + obj.access_token,
            headers: {"Content-Type": "application/json"},
            json   : data
        }, function (err, res, body) {
            console.log(body, "----")
        })
    });

需要说明的是参数中data里面的key(first, one, two,three, remark)是模版中定义的,这里需要根据模版内容来写,还有可以设置每个字段的颜色值等属性

到此消息管理这部分已经说的差不多了,咱们继续介绍。。。

第四章:微信网页开发

这个章节跟前面几章不同,前面几章介绍的是公众号开发的一些东西,这个章节介绍的是网页开发,主要针对h5应用或者是页面的开发,Worktile微信版就是微信网页开发完成的,下面咱们一步步的介绍。

  • 微信网页授权
    微信网页授权采用的是Oauth2.0的授权方式:
    第一步:访问如下链接获取code
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect 

redirect_uri是你h5地址,授权成功后会把code加入到地址上,类似于:https://weixin.worktile.com?code=xxx这样
第二步:通过code换取网页授权access_token
请求接口(get请求)

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 

返回的结果如下

{ "access_token":"ACCESS_TOKEN",    
 "expires_in":7200,    
 "refresh_token":"REFRESH_TOKEN",    
 "openid":"OPENID",    
 "scope":"SCOPE" } 

access_token是用户授权的token,openid是用户对于该公众号的唯一标示,refresh_token:可以调用刷新token的接口获取最新的token
第三步:获取用户信息(需scope为 snsapi_userinfo)
请求接口(get请求)

https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN 

通过以上3个步骤就可以获取用户的信息,进行用户的管理操作了

  • 微信JS-SDK
    网页开发中,有时候我们会自定义分享的内容,图片,音频,视频的上传,下载,地理位置,摇一摇周边,扫码,支付等的功能,这时候就需要js-sdk的开发了,下面简单介绍下js-sdk的使用,读者还可以查看官方开发文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN

    1. 绑定域名
      先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
    2. 引入JS文件
      在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
      如需使用摇一摇周边功能,请引入 http://res.wx.qq.com/open/js/jweixin-1.1.0.js
    3. 通过config接口注入权限验证配置
      如下代码需要在网页中配置

      wx.config({
      debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
      appId: '', // 必填,公众号的唯一标识
      timestamp: , // 必填,生成签名的时间戳
      nonceStr: '', // 必填,生成签名的随机串
      signature: '',// 必填,签名,见附录1
      jsApiList: [] // 必填,需要使用的JS接口列表
      });
      

      如上代码中的timestamp, nonceStr, signature需要服务端做好签名返回给页面,这里可以使用异步调用的方式,如下为服务端签名代码

      var sign = function (jsapi_ticket, url) {
      var ret = {
      jsapi_ticket: jsapi_ticket,
      nonceStr: createNonceStr(),
      timestamp: createTimestamp(),
      url: url
      };
      var string = raw(ret);
        jsSHA = require('jssha');
        shaObj = new jsSHA(string, 'TEXT');
      ret.signature = shaObj.getHash('SHA-1', 'HEX');
      return ret;
      };

      ret就是我们需要的签名结果,其中jsapi_ticket是调用ticket接口获取的,官方文档中也有说明https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token= access_token&type=jsapi, rul是获取签名的当前网页地址, nonceStr:随机字符串,timestamp:当前10位时间戳

      var raw = function (args) {
           var keys = Object.keys(args);
           keys = keys.sort()
           var newArgs = {};
          keys.forEach(function (key) {
               newArgs[key.toLowerCase()] = args[key];
          });
         var string = '';
         for (var k in newArgs) {
              string += '&' + k + '=' + newArgs[k];
        }
        string = string.substr(1);
        return string;
      };

      这个方法是对签名对象的一个字符串格式化算法

    4. 通过ready接口处理成功验证

      wx.ready(function(){
      // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
      });
    5. 调用接口
      根据config里面 jsApiList的配置可以调用js-sdk的接口,如分享朋友圈,分享微信好友等。。。

      wx.onMenuShareTimeline({
      title: '', // 分享标题
      link: '', // 分享链接
      imgUrl: '', // 分享图标
      success: function () { 
          // 用户确认分享后执行的回调函数
      },
      cancel: function () { 
          // 用户取消分享后执行的回调函数
      }
      });

      这是一个分享到朋友圈的接口,可以自定义标题,自定义链接,自定义图标
      如果想调用更多的js-sdk的接口可以参考官方文档进行开发:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN

  • 微信网页开发样式库
    https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784134&token=&lang=zh_CN

  • 微信web开发者工具
    https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_CN

以上就是微信公众号开发的一些内容,算是入门篇。其实关于微信的开发还有很多可以做的事情,而且随着需求越来越多,技术越来越完善,相信之后关于微信的开发一定还会有更多惊喜!

2016-12-15 10:04:02 Guns_NRoses 阅读数 1165
  • 微信支付开发-微信公众号开发12-微信开发php

    微信公众平台开发之微信支付开发是子恒老师《微信公众平台开发》视频教程的第12部。详细讲解了用php进行微信支付的开发。内容包含获取支付密钥,微信公众号支付开发,扫码支付,微信刷卡支付,异步处理支付结果等等。欢迎反馈,微信/QQ:68183131

    27754 人正在学习 去看看 秦子恒

package jvm;

import sun.net.www.http.HttpClient;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import net.sf.json.JSONObject;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Created by HuiSheng1 on 2016/12/15.
 */
public class WeiXinUtil {
    public static final String APPID = "APPID";
    public static final String SECRET = "SECRET";
    public static final int TIME_WAIT = 10 * 1000;
    public static long expires_in = 7200;
    public static long lastSystemCurrentTimeMillis = System.currentTimeMillis();
    public static String access_token;// 接口调用

    public static long lastSystemCurrentTimeMillisOfPage = System.currentTimeMillis();
    public static long expires_in_page = 7200;
    public static String access_token_page; // 网页授权用

    public static long lastSystemCurrentTimeMillisOfPageRefresh = System.currentTimeMillis();
    public static long expires_in_refresh = 30 * 24 * 60 * 60; // 30天过期,单位秒
    public static String refresh_token;// 网页授权刷新用

    public static String getAccessToken() {

        long timeLeft = System.currentTimeMillis() - lastSystemCurrentTimeMillis
        if (access_token == null || (timeLeft > expires_in * 1000 - TIME_WAIT && timeLeft < expires_in * 1000)) {
            String at = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRET;
            String result = getDataFromUrl(at);
            JsonSlurper json = new JsonSlurper().parseText(result);
            access_token = json.getAt("access_token").toString();
            expires_in = Long.parseLong(json.getAt("expires_in").toString());
            lastSystemCurrentTimeMillis = System.currentTimeMillis();
        }

        return access_token;
    }

    public static String getAccessTokenOfPage(String code) {
        // 通过code换取网页授权access_token
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APPID + "&secret=" + SECRET + "&code=" + code + "&grant_type=authorization_code"
        String result = getDataFromUrl(url);
        json = new JsonSlurper().parseText(result);
        access_token_page = json.getAt("access_token").toString();
        expires_in_page = Long.parseLong(json.getAt("expires_in").toString());
        refresh_token = json.getAt("refresh_token").toString();
        lastSystemCurrentTimeMillisOfPage = System.currentTimeMillis();
        lastSystemCurrentTimeMillisOfPageRefresh = System.currentTimeMillis();
//
        return refresh_token;
    }

    /**
     * 创建菜单
     */
    public static void createMenu() {
        String access_token = getAccessToken();
        //创建新菜单
        String menu = "";//要创建的微信自定义菜单
        String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
        menu_create_url = menu_create_url.replace("ACCESS_TOKEN", access_token);
        String result2 = getDataFromUrl(menu_create_url, "POST", menu);
        System.out.print(result2);

    }

    //执行访问微信接口
    public static String getDataFromUrl(String url, String methods, String menu) {
        String result = "";
        try {
            HttpClient client = new HttpClient();
            if ("GET".equals(methods)) {
                HttpMethod method = new GetMethod(url);
                client.executeMethod(method);
                result = method.getResponseBodyAsString();
                method.releaseConnection();
            } else {
                PostMethod method = new PostMethod(url);
                method.setRequestHeader("Content-Type", "text/xml;charset=utf8");
                RequestEntity requestEntity = new StringRequestEntity(menu, "text/xml", "utf8");
                method.setRequestEntity(requestEntity);
                client.executeMethod(method);
                InputStream ins = method.getResponseBodyAsStream();
                BufferedReader br = new BufferedReader(new InputStreamReader(ins, "UTF-8"));
                StringBuffer sbf = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sbf.append(line);
                }

                br.close();
                result = sbf.toString();
            }
        } catch (IOException e) {
        }
        return result;
    }

    public static String getWxAeecssToken(String code, String appid, String secret) {
        String openid_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        openid_url = openid_url.replaceAll("APPID", appid).replaceAll("SECRET", secret).replaceAll("CODE", code);
        String result = getDataFromUrl(openid_url, "GET", "");
//        System.out.println("openid result: "+result);
        JSONObject json = new JSONObject().fromObject(result);
        return json.get("access_token").toString();
    }

    //获取用户基本信息,暂时只获取是否关注公众号
    public static String getWxUserInfo(String access_token, String openid) {
        String userInfo_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
        userInfo_url = userInfo_url.replaceAll("ACCESS_TOKEN", access_token).replaceAll("OPENID", openid);
        String result = getDataFromUrl(userInfo_url, "GET", "");
        JSONObject json = new JSONObject().fromObject(result);
        //获取其他基本信息的时候需要先判断是否关注,即subscribe是否为0,如果subscribe为0,则只能得到subscribe和openid,获取其他信息会报空指针
        return json.get("subscribe").toString();
    }

    public static void main(String[] args) {
        createMenu();
    }

}

没有更多推荐了,返回首页