node.js 微信开发2-消息回复、token获取、自定义菜单
项目结构
>config/wechat.json 微信公众号的配置文件
>controllers/oauth.js 微信网页授权接口(下一篇再细讲讲)
>controllers/wechat.js 微信公众号接口(包括接入接口和其他调用微信api的接口)
>wechat/access_token.json 请求微信api接口之前都需要使用的access_token
>wechat/crytoGraphy.js 加密解密文件(这里使用的是明文方式,未用到)
>wechat/menus.json 微信公众号的自定义菜单
>wechat/wechat.js 调用微信api的方法
项目的架构说明和使用步骤可以参考前面一篇的‘node.js 接口调用示例’:https://www.cnblogs.com/eye-like/p/11743744.html
一些说明点
1、公众号的接入接口和接收消息接口
两个接口的地址是一致的,区别是:
> 接入接口是GET请求,需要的是对get的接口参数进行解析验证,然后按需返回就可以了
> 接收消息接口是POST请求,需要先解析微信发送过来的消息,然后根据情况决定是否返回消息
- WeChat.prototype.handleMsg = async function (ctx) {
- return new Promise((resolve, reject) => {
- // let req = ctx.request;
- // let res = ctx.response;
- let req = ctx.req;
- var buffer = [],
- that = this;
- //实例微信消息加解密
- // var cryptoGraphy = new CryptoGraphy(that.config,ctx.request);
- //监听 data 事件 用于接收数据
- req.on('data', function (data) {
- // logger.info("on data", data);
- buffer.push(data);
- });
- req.on('end', function () {
- // logger.info("on end");
- var msgXml = Buffer.concat(buffer).toString('utf-8');
- parseString(msgXml, {
- explicitArray: false
- }, function (err, result) {
- // logger.info("on result", result);
- result = result.xml;
- resolve(result)
- })
- });
- })
- },
接收微信消息
* 接收消息使用的是Promise函数封装,目的是将微信的收发消息两块做隔离
* 涉及到node.js 接收post参数的方式,需要ctx.req.on('data',function(){})方法接受参数,并在ctx.req.on(‘end’,function(){})函数中接受最终的获取参数
* 因为微信发过来的消息是xml格式,所以在node.js 中需要xml2js模块(非node.js内置模块,需要先安装依赖)将xml文件解析
- /**
- * 微信消息回复
- * @param {ctx} context 对象
- * @param {result} 微信消息
- */
- WeChat.prototype.responseMsg = function (ctx, result) {
- var toUser = result.ToUserName; //接收方微信
- var fromUser = result.FromUserName; //发送仿微信
- var reportMsg = ""; //声明回复消息的变量
- if (result.MsgType.toLowerCase() === "event") {
- //判断事件类型
- switch (result.Event.toLowerCase()) {
- case 'subscribe':
- //回复消息
- var content = "欢迎关注 线上随访 公众号\n";
- content += "我们致力于帮助出院康复病人与医生建立便捷的沟通渠道~\n";
- reportMsg = msg.txtMsg(fromUser, toUser, content);
- break;
- case 'click':
- var contentArr = [{
- Title: "Node.js 微信自定义菜单",
- Description: "使用Node.js实现自定义微信菜单",
- PicUrl: "http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72868520"
- },
- {
- Title: "Node.js access_token的获取、存储及更新",
- Description: "Node.js access_token的获取、存储及更新",
- PicUrl: "http://img.blog.csdn.net/20170528151333883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72783631"
- },
- {
- Title: "Node.js 接入微信公众平台开发",
- Description: "Node.js 接入微信公众平台开发",
- PicUrl: "http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72765279"
- }
- ];
- //回复图文消息
- reportMsg = msg.graphicMsg(fromUser, toUser, contentArr);
- break;
- }
- } else {
- //判断消息类型为 文本消息
- if (result.MsgType.toLowerCase() === "text") {
- switch (result.Content) {
- case '':
- reportMsg = msg.txtMsg(fromUser, toUser, 'Hello ,线上随访公众号开通了,快来使用吧……');
- break;
- case '':
- reportMsg = msg.txtMsg(fromUser, toUser, 'Ha Ha,我还有更多的功能待发掘呢,敬请期待吧……');
- break;
- case '文章':
- var contentArr = [{
- Title: "Node.js 微信自定义菜单",
- Description: "使用Node.js实现自定义微信菜单",
- PicUrl: "http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72868520"
- },
- {
- Title: "Node.js access_token的获取、存储及更新",
- Description: "Node.js access_token的获取、存储及更新",
- PicUrl: "http://img.blog.csdn.net/20170528151333883?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72783631"
- },
- {
- Title: "Node.js 接入微信公众平台开发",
- Description: "Node.js 接入微信公众平台开发",
- PicUrl: "http://img.blog.csdn.net/20170605162832842?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHZrQ29kZXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast",
- Url: "http://blog.csdn.net/hvkcoder/article/details/72765279"
- }
- ];
- //回复图文消息
- reportMsg = msg.graphicMsg(fromUser, toUser, contentArr);
- break;
- default:
- reportMsg = msg.txtMsg(fromUser, toUser, '没有这个选项哦');
- break;
- }
- // logger.info("on reportMsg", reportMsg);
- }
- }
- //返回给微信服务器
- ctx.body = reportMsg
- },
回复微信消息
# 主要任务是根据微信消息的类型‘MsgType’,来执行不同的动作
# 事件推送消息(MsgType==‘event’)
* 关注取消事件 subscribe,unsubscribe
此时可以做数据库接入录入订阅者信息或者更新订阅者信息
* 扫描带参数二维码事件
用户未关注时:qrscene_ +二维码参数值
用户已关注时:scan
* 上报地理位置事件 LOCATION
* 自定义菜单事件 CLICK
# 普通消息推送 (MsgType=='text')
可分为 文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息
2、有参考的node.js 发送get、post请求的两个方法
- /**
- * 用于处理 https Get请求方法
- * @param {String} url 请求地址
- */
- this.requestGet = function (url) {
- return new Promise(function (resolve, reject) {
- https.get(url, function (res) {
- var buffer = [],
- result = "";
- //监听 data 事件
- res.on('data', function (data) {
- buffer.push(data);
- });
- //监听 数据传输完成事件
- res.on('end', function () {
- result = Buffer.concat(buffer).toString('utf-8');
- //将最后结果返回
- resolve(result);
- });
- }).on('error', function (err) {
- reject(err);
- });
- });
- }
node.js 发送get请求
- /**
- * 用于处理 https Post请求方法
- * @param {String} url 请求地址
- * @param {JSON} data 提交的数据
- */
- this.requestPost = function (url, data) {
- return new Promise(function (resolve, reject) {
- //解析 url 地址
- var urlData = urltil.parse(url);
- //设置 https.request options 传入的参数对象
- var options = {
- //目标主机地址
- hostname: urlData.hostname,
- //目标地址
- path: urlData.path,
- //请求方法
- method: 'POST',
- //头部协议
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Content-Length': Buffer.byteLength(data, 'utf-8')
- }
- };
- var req = https.request(options, function (res) {
- var buffer = [],
- result = '';
- //用于监听 data 事件 接收数据
- res.on('data', function (data) {
- buffer.push(data);
- });
- //用于监听 end 事件 完成数据的接收
- res.on('end', function () {
- result = Buffer.concat(buffer).toString('utf-8');
- resolve(result);
- })
- })
- //监听错误事件
- .on('error', function (err) {
- console.log(err);
- reject(err);
- });
- //传入数据
- req.write(data);
- req.end();
- });
- }
- }
node.js 发送post请求
注:使用前需要引用内置的https中间件
3、关于access_token
调用微信接口的时候都需要发送微信接口凭证access_token(除微信网页授权中获取的access_token并不是这个access_token),因此请求微信接口的第一步都是要先获取这个access_oken
- /**
- * 获取微信 access_token
- */
- WeChat.prototype.getAccessToken = function () {
- var that = this;
- return new Promise(function (resolve, reject) {
- //获取当前时间
- var currentTime = new Date().getTime();
- //格式化请求地址
- var url = util.format(that.apiURL.accessTokenApi, that.apiDomain, that.appID, that.appScrect);
- //判断 本地存储的 access_token 是否有效
- if (accessTokenJson.access_token === "" || accessTokenJson.expires_time < currentTime) {
- that.requestGet(url).then(function (data) {
- var result = JSON.parse(data);
- if (data.indexOf("errcode") < ) {
- accessTokenJson.access_token = result.access_token;
- accessTokenJson.expires_time = new Date().getTime() + (parseInt(result.expires_in) - ) * ;
- //更新本地存储的
- fs.writeFile('./wechat/access_token.json', JSON.stringify(accessTokenJson));
- //将获取后的 access_token 返回
- resolve(accessTokenJson.access_token);
- } else {
- //将错误返回
- resolve(result);
- }
- });
- } else {
- //将本地存储的 access_token 返回
- resolve(accessTokenJson.access_token);
- }
- });
- }
获取access_token
- var url = util.format(that.apiURL.accessTokenApi, that.apiDomain, that.appID, that.appScrect);
url参数依次为:
that.apiURL.accessTokenApi:"%scgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
that.apiDomain:"https://api.weixin.qq.com/"
that.appID:公众号的appID
that.appScrect:公众号的密匙
请求后获取的accee_token 有效时间为7200s,在此时间内,再次请求微信接口都可以使用已经缓存的accee_token
4、关于菜单
最好是在请求接口的时候加入请求密匙(如oauth2认证),尤其是更新和删除
git:https://github.com/wuyongxian20/wechat-api
node.js 微信开发2-消息回复、token获取、自定义菜单的更多相关文章
- node.js 微信开发1-接入
准备工作1 域名准备 无论是个人开发还是做公司项目域名都是必不可少的 前期我个人用过花生壳做个开发测试,挺好用的,就是现在要收费了,开通花生壳要收费,开通内网穿透要收费(为啥要内网穿透呢,因为微信接入 ...
- node.js 微信开发3-网页授权
1.配置公众号的自定义菜单,如 { "button":[ { "type":"view", "name":"公 ...
- node JS 微信开发
JS-SDK 要点 微信测试号; 扫码登录;无需认证(只是名称统一为微信测试号)http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/logi ...
- 4.Node.js 微信消息管理
一.写在前面的话 当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应. 消息推送也是 ...
- vue+node.js+webpack开发微信公众号功能填坑——v -for循环
页面整体框架实现,实现小功能,循环出数据,整体代码是上一篇 vue+node.js+webpack开发微信公众号功能填坑--组件按需引入 修改部门代码 app.vue <yd-flexbox&g ...
- Force.com微信开发系列(四)申请Access Token及自定义菜单之创建菜单
在微信接口开发中,许多服务的使用都离不开Access Token,Access Token相当于打开这些服务的钥匙,正常情况下会在7200秒内失效,重复获取将导致上次获取的Token失效,本文将首先介 ...
- node.js之开发环境搭建
一.安装linux系统 (已安装linux可跳此步骤) 虚拟机推荐选择:VirtualBox 或者 Vmware (专业版永久激活码:5A02H-AU243-TZJ49-GTC7K-3C61N) 我这 ...
- AngularJS + Node.js + MongoDB开发
AngularJS + Node.js + MongoDB开发的基于位置的通讯录(by vczero) 一.闲扯 有一天班长说了,同学们希望我开发一个可以共享位置的通讯录,于是自己简单设计了下功能.包 ...
- Ubuntu 14.04下搭建Node.js的开发环境
最近想找一个轻量级且支持快速开发的服务开发平台,选来选去选择了Node.js,当时有几种选择: Python + Django(用过Django,虽然开发快速,但是感觉性能并不太好). Ruby + ...
随机推荐
- getField和getDeclaredField的区别
这两个方法都是用于获取字段getField 只能获取public的,包括从父类继承来的字段.getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段. ...
- k8s记录-kubeadm安装(一)(转载)
配置 kubeadm 概述 安装 kubernetes 主要是安装它的各个镜像,而 kubeadm 已经为我们集成好了运行 kubernetes 所需的基本镜像.但由于国内的网络原因,在搭建环境时,无 ...
- Xilinx Zynq-7000 嵌入式系统设计与实现
Xilinx Zynq-7000 嵌入式系统设计与实现 基于ARM Cortex-A9双核处理器和Vivado的设计方法 目录 第1章Zynq-7000 SoC设计导论 1.1全可编程片上系统基础知识 ...
- 数据结构与抽象 Java语言描述 第4版 pdf (内含标签)
数据结构与抽象 Java语言描述 第4版 目录 前言引言组织数据序言设计类P.1封装P.2说明方法P.2.1注释P.2.2前置条件和后置条件P.2.3断言P.3Java接口P.3.1写一个接口P.3. ...
- EC11编码器的使用方法
1. EC11编码器的原理图如下 2. 旋转的时候,波形如下,EC11转1格,产生一个上升沿的中断,思路就是检测AX4-1的上升沿中断(平时是低电平),进入中断服务函数,检测AX4-2的电平,低电平逆 ...
- 微信小程序bug集
bug1:navigator标签无法跳转,控制台不报错,解决方案如图
- svn查看登录过的账号密码
直接下载:http://www.leapbeyond.com/ric/TSvnPD/
- jenkins publish .net core application to linux server
最近学习Docker与Jenkins, 网上大部分都是关于Jenkins+Git+Docker进行持续远程部署, 我一直在考虑为什么Jenkins和Docker要绑定一块使用, 因为我想单独使用Jen ...
- MongoDB 空间定位(点) 与 距离检索
转自: http://blog.csdn.net/flamingsky007/article/details/39208837 基于 MongoDB 2.6 GeoJSON 格式 { "ty ...
- Python-18-类的内置属性
1. __getattr__.set__attr__.__delattr__ class Foo: x=1 def __init__(self,y): self.y=y def __getattr__ ...