4.Node.js 微信消息管理
一、写在前面的话
当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应。
消息推送也是微信公众号开发更为有趣的功能,涉及到文本消息、图片消息、语音消息、视频消息、音乐消息以及图文消息。并且最为有趣的功能当属消息加解密了,当然由于篇文章篇幅的原因我会在下一篇文章中去着重说明。
二、微信消息管理
1.捕获消息信息
在文章的第一句话中,为我们指明了微信消息产生的请求方式为 POST,因此首先我们就去对 Node.js 的 Post 请求进行监听。
在我们的 app.js 文件中添加一个POST监听,并将获取的结果输出:
//用于处理所有进入 3000 端口 post 的连接请求
app.post('/',function(req,res){
var buffer = [];
//监听 data 事件 用于接收数据
req.on('data',function(data){
buffer.push(data);
});
//监听 end 事件 用于处理接收完成的数据
req.on('end',function(){
//输出接收完成的数据
console.log(Buffer.concat(buffer).toString('utf-8'));
});
});
随后将 Node.js 启动后映射至外网,关注我们的微信公众号,在控制台中则会看到:
打开 微信帮助文档,点击左侧菜单的消息管理,选择其子菜单 接收事件推送,如图:
从上图我们不难看出,微信 接收事件推送 确实很多,而我们最终目标是要实现,在用户触发事件时返回其相应的回复消息。因此我们总结一下我们要实现的步骤:
- 解析 XML ,使用 Event 参数判断事件类型
- 返回相应的事件信息
总结完实现步骤后,我们就开始动手实现第一个被动回复消息吧。
2.以关注事件为例,实现第一个被动回复
解析 XML 我这里使用了 第三方的包 xml2js(npm install xml2js ),并在 wechat.js 中引入。
parseString = require('xml2js').parseString;//引入xml2js包
为 WeChat 对象添加一个消息处理的方法 handleMsg,将 app.js 中捕获 POST 实现的写入在其代码块中,并使用 xml2js 解析,代码如下
/**
* 微信消息
*/
WeChat.prototype.handleMsg = function(req,res){
var buffer = [];
//监听 data 事件 用于接收数据
req.on('data',function(data){
buffer.push(data);
});
//监听 end 事件 用于处理接收完成的数据
req.on('end',function(){
var msgXml = Buffer.concat(buffer).toString('utf-8');
//解析xml
parseString(msgXml,{explicitArray : false},function(err,result){
if(!err){
//打印解析结果
console.log(result);
}else{
//打印错误信息
console.log(err);
}
})
});
}
在 app.js 中调用 handleMsg 方法
//用于处理所有进入 3000 端口 post 的连接请求
app.post('/',function(req,res){
wechatApp.handleMsg(req,res);
});
完成了代码的编写后,将公众号重新关注
最后打印为一个 JSON 格式的结果,也就是预示着我们第1步工作已经完成。下面开始我们的第2步,微信被动回复。
在文章的第一句话的后边提到 开发者可以在响应包(Get)中返回特定XML结构,那么这个特定的 XML 结构在哪呢?再次打开微信帮助文档,点击左侧菜单的消息管理,选择其子菜单 被动回复消息,如图:
直接来到 回复文本消息:
拿到回复文本消息格式后,我们就来为关注我们公众号的同学打声招呼吧。在 wechat 文件中 创建 msg.js 文件用于消息的管理。
并在 msg.js 中添加处理文本消息的接口,并在 wechat.js 中引用
'use strict' //设置为严格模式
//回复文本消息
exports.txtMsg = function(toUser,fromUser,content){
var xmlContent = "<xml><ToUserName><![CDATA["+ toUser +"]]></ToUserName>";
xmlContent += "<FromUserName><![CDATA["+ fromUser +"]]></FromUserName>";
xmlContent += "<CreateTime>"+ new Date().getTime() +"</CreateTime>";
xmlContent += "<MsgType><![CDATA[text]]></MsgType>";
xmlContent += "<Content><![CDATA["+ content +"]]></Content></xml>";
return xmlContent;
}
修改 wechat.js 中 handleMsg 方法
/**
* 微信消息
*/
WeChat.prototype.handleMsg = function(req,res){
var buffer = [];
//监听 data 事件 用于接收数据
req.on('data',function(data){
buffer.push(data);
});
//监听 end 事件 用于处理接收完成的数据
req.on('end',function(){
var msgXml = Buffer.concat(buffer).toString('utf-8');
//解析xml
parseString(msgXml,{explicitArray : false},function(err,result){
if(!err){
result = result.xml;
var toUser = result.ToUserName; //接收方微信
var fromUser = result.FromUserName;//发送仿微信
//判断事件类型
switch(result.Event.toLowerCase()){
case 'subscribe':
//回复消息
res.send(msg.txtMsg(fromUser,toUser,'欢迎关注 hvkcoder 公众号,一起斗图吧'));
break;
}
}else{
//打印错误信息
console.log(err);
}
})
});
}
没错就是这么简单。这里有个逻辑是这样的 toUser 表示接收方,也就是咱们的微信公众号;fromUser 表示发送方,也就是触发事件的用户。而我们要回复用户时,此时 接收方 就是 触发事件的用户,而发送方则是 我们的微信公众号。这块比较绕,大家可以慢慢去理解。
由于我们还没有对微信的素材管理进行讲解,这里我们暂时跳过 图片消息、语音消息、视频消息、以及音乐消息。直接实现图文消息的推送。
3.图文消息
在 msg.js 文件中添加图文XML模板
//回复图文消息
exports.graphicMsg = function(toUser,fromUser,contentArr){
var xmlContent = "<xml><ToUserName><![CDATA["+ toUser +"]]></ToUserName>";
xmlContent += "<FromUserName><![CDATA["+ fromUser +"]]></FromUserName>";
xmlContent += "<CreateTime>"+ new Date().getTime() +"</CreateTime>";
xmlContent += "<MsgType><![CDATA[news]]></MsgType>";
xmlContent += "<ArticleCount>"+contentArr.length+"</ArticleCount>";
xmlContent += "<Articles>";
contentArr.map(function(item,index){
xmlContent+="<item>";
xmlContent+="<Title><![CDATA["+ item.Title +"]]></Title>";
xmlContent+="<Description><![CDATA["+ item.Description +"]]></Description>";
xmlContent+="<PicUrl><![CDATA["+ item.PicUrl +"]]></PicUrl>";
xmlContent+="<Url><![CDATA["+ item.Url +"]]></Url>";
xmlContent+="</item>";
});
xmlContent += "</Articles></xml>";
return xmlContent;
}
}
更改 wechat.js 文件中的 handleMsg 方法,将图消息推送响应在点击事件中
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"}
];
//回复图文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
点击菜单下的 今日推荐
图文推送就是这么简单的被我们给实现了。
4.接收普通消息
微信除了为我们接收事件推送外,千万不要忘了微信还能通过发送文字。而这一节我们也就来玩玩微信接收普通消息。
打开 微信帮助文档,点击左侧菜单的消息管理,选择其子菜单 接收普通消息,如图:
依然如接收事件推送的套路,不同的是参数发生了改变,但这并步影响我们的开发,只需要几步就能够完美的解决。更改 wechat.js 文件 handleMsg方法,这里我先暂时只针对用户输入的文本消息做处理,其他的跟其类似。
//判断消息类型
if(result.MsgType.toLowerCase() === "event"){
//判断事件类型
switch(result.Event.toLowerCase()){
case 'subscribe':
//回复消息
var content = "欢迎关注 hvkcoder 公众号,一起斗图吧。回复以下数字:\n";
content += "1.你是谁\n";
content += "2.关于Node.js\n";
content += "回复 “文章” 可以得到图文推送哦~\n";
res.send(msg.txtMsg(fromUser,toUser,''));
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"}
];
//回复图文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
}
}else{
//判断消息类型为 文本消息
if(result.MsgType.toLowerCase() === "text"){
//根据消息内容返回消息信息
switch(result.Content){
case '1':
res.send(msg.txtMsg(fromUser,toUser,'Hello !我的英文名字叫 H-VK'));
break;
case '2':
res.send(msg.txtMsg(fromUser,toUser,'Node.js是一个开放源代码、跨平台的JavaScript语言运行环境,采用Google开发的V8运行代码,使用事件驱动、非阻塞和异步输入输出模型等技术来提高性能,可优化应用程序的传输量和规模。这些技术通常用于数据密集的事实应用程序'));
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"}
];
//回复图文消息
res.send(msg.graphicMsg(fromUser,toUser,contentArr));
break;
default :
res.send(msg.txtMsg(fromUser,toUser,'没有这个选项哦'));
break;
}
}
}
OK !至此我们就完成了微信消息管理的讲解,似乎真的没有什么难度。预留了一章,主要想要去细说一下说消息加解密,因为在网上涉及 Node.js 微信消息加解密的文章确实很少,微信帮助文档给的案例也没有 Node.js 的详细说明。
最后文章代码部分,由于网上编辑器的代码换行做的不是很好可能有些乱,建议可以去我的 github 上查看源码。
文章源代码:https://github.com/SilenceHVK/wechatByNode 。对文章有不正确之处,请给予纠正。github源代码请顺手给个 Star,最后感谢您的阅读。
文章目录:
1.Node.js 接入微信公众平台开发
2.Node.js access_token的获取、存储及更新
3.Node.js 自定义微信菜单
4.Node.js 微信消息管理
4.Node.js 微信消息管理的更多相关文章
- Node.js的进程管理
众所周知Node基于V8,而在V8中JavaScript是单线程运行的,这里的单线程不是指Node启动的时候就只有一个线程,而是说运行JavaScript代码是在单线程上,Node还有其他线程,比如进 ...
- node.js 微信开发2-消息回复、token获取、自定义菜单
项目结构 >config/wechat.json 微信公众号的配置文件 >controllers/oauth.js 微信网页授权接口(下一篇再细讲讲) >controllers/we ...
- node.js 微信开发1-接入
准备工作1 域名准备 无论是个人开发还是做公司项目域名都是必不可少的 前期我个人用过花生壳做个开发测试,挺好用的,就是现在要收费了,开通花生壳要收费,开通内网穿透要收费(为啥要内网穿透呢,因为微信接入 ...
- node.js Websocket消息推送---GoEasy
Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送 速度快,代码简单易懂上手快 浏览器兼容性:GoEasy推送 支持websocket ...
- Node.js的安装以及Node.js的模块管理
索引: Node.js的安装以及Node.js的模块管理Node.js开发环境搭建以及对ES6的支持Node.js构建Vue.js项目Vue.js单文件组件的开发基于Vue.js的UI组件(Eleme ...
- 使用yarn代替npm作为node.js的模块管理器
使用yarn代替npm作为node.js的模块管理器 转 https://www.jianshu.com/p/bfe96f89da0e Fast, reliable, and secure d ...
- 90%的人都不知道的Node.js 依赖关系管理(下)
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文参考:https://dzone.com/articles/node-dependency-manage ...
- node.js微信小程序配置消息推送
在开发微信小程序时,有一个消息推送,它的解释是这样的. 消息推送具体的内容是下面的这个网址 https://developers.weixin.qq.com/miniprogram/dev/fra ...
- Node.js 安装与管理
一.node安装 Windows下,官网下载 Node.js 安装包,运行安装即可, 安装成功后,可查看版本号 node -v 二.npm npm 是 node 包管理工具,随同node一起安装,安装 ...
随机推荐
- JavaScript分支语句if, else if, switch 案例详解
if语句主要是在需要判断,或者在可知有多少种情形时使用的语句.A==B?"A等于B";"A不等于B"; 基本结构: if(判断条件){ ...
- 2017-4-24 WinForm开发基础、窗体的属性CenterScreen
WinForm中文名称: Windows窗体,是·Net开发平台中对Windows Form的一种称谓. 客户端应用程序:C/S 客户端很重要的特点:可以操作用户电脑上的文件 窗体属性:窗体种类: + ...
- LinkCode 下一个排列、上一个排列
http://www.lintcode.com/zh-cn/problem/next-permutation-ii/# 原题 给定一个若干整数的排列,给出按正数大小进行字典序从小到大排序后的下一个排列 ...
- Composer 安装(一)
一.简介 Composer 是 PHP 用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer 会帮你安装这些依赖的库文件. ...
- SVM流行库LIBSvm的使用和调参
简介:Libsvm is a simple, easy-to-use, and efficient software for SVM classification and regression. It ...
- 使用Nodejs进行反向代理
在实际工程开发中,会有前后端分离的需求. 为了平滑的完成前端请求到后端各个独立服务,需要一个中间件实现请求转发的功能,利用Nginx可以实现,在这里,使用nodejs实现一个反向代理服务器. 实际 ...
- 高性能日志类KLog(已开源代码)
项目开源地址:https://github.com/ihambert/KLog 上回介绍了超简易日志类,但他有诸多的局限性,注定了不能作为一个网站的日志类. 那什么样的日志类才能用于网站呢.首先来假 ...
- AngularJS的相关应用
一.[AngularJS常用指令] 1.ng-app:声明Angular所管辖的区域.一般写在body或html上,原则上一个页面只有一个: <body ng- ...
- java局部/成员/静态/实例变量
局部变量和成员变量主要是他们作用域的区别成员变量个是类内部:局部变量是定义其的方法体内部(或者方法体内部的某一程序块内——大括号,主要看定义的位置).另外,成员变量可以不显式初始化,它们可以由系统设定 ...
- Telegram学习解析系列(二):这我怎么给后台传输数据?
写在前面: 在iOS开发的过程中,有很多时候我们都在和数据打交道,最基本的就是数据的下载和上传了,估计很多很多的小伙伴都在用AFNetworking与后台数据打交道,可有没有想过,哪天AFNetwor ...