上篇说到微信开发配置,接下来着手开发,我们先来看看文本消息的接收与自动回复:
接收普通消息–当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上,当服务器接收到消息,服务器如果没有做出回应,会断开连接并重新发起请求,重复三次操作,若还未作出回应便回复xxx直接看图:

实现思路,通过构建构造函数,将实例方法绑定在原型对象上,然后将方法导出,微信返回和接收的数据格式都是xml,所以我们要对xml进行转换。所以在今天我们会引入几个新的模块。代码如下(wechat.js):

var sha1 = require("sha1");
var parseString = require('xml2js').parseString;
var msg = require("../common/msg");
var request = require("request");
var path = require("path");
var fs = require("fs");
var util = require("util");
var accessTokenJson = require("../config/access_token.json");
function Wechat(config) {this.config = config;this.token = config.wechat.token;this.appID = config.wechat.appID;this.appScrect = config.wechat.appSecret;this.prefix = config.wechat.prefix;this.diyApi = config.wechat.diyApi;
}
Wechat.prototype.autoMsg = function (req, res, next) {var buffer = [];var that = this;req.on('data', function (data) {buffer.push(data);});req.on('end', function () {var msgXml = Buffer.concat(buffer).toString('utf-8');parseString(msgXml, { explicitArray: false }, function (err, result) {if (err) throw err;result = result.xml;// console.log(result);var toUser = result.ToUserName;var fromUser = result.FromUserName;//回复普通消息if (result.MsgType === "text") {res.send(msg.textMsg(toUser, fromUser, msg.message(result.Content)));} else if (result.MsgType === "image") {//回复图片//在这里图片相当于素材,用户发送的素材只是临时素材,只能在微信服务器保存三天,回复思路://先上传素材---先封装一个post请求,然后通过素材接口获取media_id来获取素材//上传素材就需要封装post get以及素材上传的api//注意在上传素材时需要access_token所以也需要封装获取access_token的apivar urlPath = path.join(__dirname, "../material/timg.jpg");that.uploadFile(urlPath, "image").then(function (mdeia_id) {resultXml = msg.imgMsg(fromUser, toUser, mdeia_id);res.send(resultXml);})}})})
};
//获取access_token
//为什么要保存access_token,原因请查看文档
Wechat.prototype.getAccessToken = function () {var that = this;return new Promise(function (resolve, reject) {var currentTime = new Date().getTime();//格式化请求地址,把刚才的%s按顺序替换var url = util.format(that.diyApi.getAccessToken, that.prefix, 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);// console.log(result);if (data.indexOf("errcode") < 0) {accessTokenJson.access_token = result.access_token;accessTokenJson.expires_time = new Date().getTime() + (parseInt(result.expires_in) - 200) * 1000;// console.log(accessTokenJson);//更新本地存储的fs.writeFile('./../config/access_token.json', JSON.stringify(accessTokenJson),function(err){if(err){throw err;}else{console.log("access_token失效,重新写入成功!");}});resolve(accessTokenJson.access_token);} else {resolve(result);}});} else {//将本地存储的 access_token 返回resolve(accessTokenJson.access_token);}});
}
//封装一个get方法
Wechat.prototype.requestGet = function (url) {return new Promise(function (resolve, reject) {request(url, (error, response, body) => {resolve(body);})})
}
//封装一个post方法
Wechat.prototype.requestPost = function (url, data) {return new Promise(function (resolve, reject) {request.post({ url: url, formData: data }, function (err, httpResponse, body) {resolve(body);});});
}//上传素材
Wechat.prototype.uploadFile = function (urlPath, type) {var that = this;return new Promise(function (resolve, reject) {that.getAccessToken().then(function (data) {//data=== access_tokenvar form = { //构造表单media: fs.createReadStream(urlPath)}var url = util.format(that.diyApi.uploadFile, that.prefix, data, type);that.requestPost(url, form).then(function (result) {resolve(JSON.parse(result).media_id);})})})
}

代码优化部分:msg.js
将文字回复和图片恢复的api都抽出来放于一个新的js文件,代码如下:

//回复文字消息
exports.textMsg = function (toUser, fromUser, content) {var resultXml = "<xml><ToUserName><![CDATA[" + fromUser + "]]></ToUserName>";resultXml += "<FromUserName><![CDATA[" + toUser + "]]></FromUserName>";resultXml += "<CreateTime>" + new Date().getTime() + "</CreateTime>";resultXml += "<MsgType><![CDATA[text]]></MsgType>";resultXml += "<Content><![CDATA[" + content + "]]></Content></xml>";return resultXml;
}
//设置自动回复内容
exports.message = function (data) {console.log(data)var content;if (data === "你好" || data === "hello" || data === "hi") {content = "欢迎光临小许客栈!"} else {content = "公众号还在升级,敬请期待!";}return content;
}
//回复图片消息
exports.imgMsg = function(toUser, fromUser, media_id) {var xmlContent = "<xml><ToUserName><![CDATA["+ toUser +"]]></ToUserName>";xmlContent += "<FromUserName><![CDATA["+ fromUser +"]]></FromUserName>";xmlContent += "<CreateTime>"+ new Date().getTime() +"</CreateTime>";xmlContent += "<MsgType><![CDATA[image]]></MsgType>";xmlContent += "<Image><MediaId><![CDATA["+ media_id +"]]></MediaId></Image></xml>";return xmlContent;
}

app.js

var Wechat = require('./routes/wechat');
var wechat = new Wechat(config); //实例化一个WeChat对象
app.get('/', (req,res,next)=>{wechat.auth(req,res,next);
});
app.post("/",(req,res,next)=>{wechat.autoMsg(req,res,next);
});

注意看代码注释,比较重要!!!
接下来看下效果:

nodejs+express对微信公众号进行二次开发--接收消息,自动回复文本,图片以及代码优化相关推荐

  1. nodejs+express解决微信公众号token验证失败

    nodejs+express解决微信公众号token验证失败 问题描述 下面是服务端代码 问题原因 解决方案 重新运行服务器问题解决 结语 问题描述 这里是测试号的状态,如果是公众号的话上边应该显示t ...

  2. 微信公众号的二次开发(二 自定义菜单的创建)

    在上篇<微信公众号的二次开发(一)>我们介绍了微信订阅号的一些坑, 以及微信公众平台开发的一些基本配置.下面我们继续介绍如何通过用户关注等行为.获取用户的openid. 自定义微信公众号菜 ...

  3. 如何判断微信公众号是否二次开发(一)

    微信公众号是否二次开发,即微信公众号是否使用了公众平台开发接口(其中主要如:自定义菜单接口.配置第三方开发服务器接口.调用外部链接等). 接下来介绍如何用手机直观的去判断微信公众号是否二次开发,主要从 ...

  4. 微信公众号的二次开发(三、接收事件推送获取用户信息)

    在上篇<微信公众号的二次开发(二 自定义菜单的创建)>中我们介绍了自定义菜单的创建.本篇文章将介绍如何通过接收事件推送来获取用户信息.首先我们阅读官方文档: 根据官方文档的介绍 微信公众号 ...

  5. 微信公众号的二次开发(一 订阅号没有获取网页授权的解决方法)

    前言 应公司开发需求,最近需要进行公众号的二次开发.经过系列讨论,最后确定为使用订阅号来开发. 因为公众号开发要获取微信用户的基本信息,需要通过用户授权获取code,然后去换取openid,最后在获取 ...

  6. 微信公众号php二次开发,微信公众号开发之文本消息自动回复php代码

    本文实例为大家分享了php微信文本消息自动回复 别代码,供大家参考,具体内容如下 1.PHP示例代码下载 下载地址1:http://xiazai.jb51.net/201608/yuanma/phpw ...

  7. 微信扫码登录,微信公众号生成二维码,关注登录nodejs+vue

    微信公众号生成二维码,关注后扫码登录 技术栈为nodejs+vue 有不懂的可以加我微信yizheng369 1.效果 初始: 关注后: 2.源码 此项目为前后端分离项目,前后端代码都在这个仓库里, ...

  8. Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

    接入微信公众平台开发,开发者需要按照如下步骤完成: 1.填写服务器配置 2.验证服务器地址的有效性 3.依据接口文档实现业务逻辑 资料准备: 1.一个可以访问的外网,即80的访问端口,因为微信公众号接 ...

  9. 微信公众号无需二次登录_您无需两次解决问题-您需要一个设计系统

    微信公众号无需二次登录 重点 (Top highlight) The design system concept can be differently defined according to eac ...

最新文章

  1. 是知当代之士、驰骛之曹,书读纵横,则思诸侯之变
  2. matlab中基本函数的用法
  3. mysql update锁_mysql中update语句的锁
  4. .net MySQL事物_在ASP.NET 2.0中操作数据之六十一:在事务里对数据库修改进行封装...
  5. Git 查看并修改 name 和 email
  6. Tensorflow 之 name/variable_scope 变量管理
  7. 纵览神经架构搜索方法
  8. idea 中maven编译速度过慢的问题的解决
  9. 【文献阅读】ResNet-Deep Residual Learning for Image Recognition--CVPR--2016
  10. python两组数的差异 pca_python – scikit KernelPCA不稳定的结果
  11. 11个免费高清图片下载站
  12. docker build 时出现no space left on device解决方法
  13. 物联网新零售项目 订单支付与出货控制
  14. Arduino 各种模块篇 震动模块 常开 震动传感器模块
  15. java基于springboot+vue的驾校学车报名预约管理系统 nodejs+element
  16. ife2018 零基础学院 day 4
  17. 『每周译Go』那些年我使用Go语言犯的错
  18. Ubuntu修改终端下的语言(中文或英文)
  19. 百度地图JS API制作专题图
  20. bak文件转换成sql文件_数据库bak文件转sql

热门文章

  1. ADSP-21489的开发详解:VDSP+自己编程写代码开发(1-如何来做21489和21479的开发?简单说两句)
  2. 简述信息系统安全设计要考虑的几个层面,每个层面可能存在的安全威胁及其应对措施
  3. OkHttp3设置Content-Type
  4. IGX 8400 系列交换机
  5. py读shp文件_入门-Python-读取Shapefile
  6. 【C语言】 求水仙花数
  7. 了解一下高速动态称重产品
  8. 零基础怎么学会计实操?
  9. IP通讯名词解释-BLF(Busy Lamp Field)
  10. 【Pandas】筛选某列过滤