100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 学习微信开发公众号的第一天(根据文字自动回复文字)

学习微信开发公众号的第一天(根据文字自动回复文字)

时间:2019-12-13 19:36:41

相关推荐

学习微信开发公众号的第一天(根据文字自动回复文字)

一.验证服务器的有效性

1.安装ngrok实现内网穿透

2.将最外层的包拖拽到控制台使用npm init初始化

3.安装express模块 使用npm i express命令

4.将ngrok的数据写入微信接口信息 使用Webstorm接受消息

//引入express模块const express = require("express");//创建app应用对象const app = express();//验证服务器有效性// ngrok http 3000app.use((req,res,next) =>{console.log(req.query);})//监听端口号app.listen(3000,() => console.log('服务器启动成功'));

5.验证消息是否来自微信服务器

// 1.验证消息是否来自微信服务器// 目的:计算得出signature与微信传过来的值相比较// 1.1将微信加密签名的三个参数(timestamp,nonce,token)按照字典序排序组合在一起成一个数组// 1.2将数组里面所有参数拼接成一个字符串,进行sha1加密// 1.3加密完成生成signature,与微信服务器发过来的进行比较// 如果一样 返回echostr给微信服务器// 如果不一样说明不是来自微信服务器 返回error

5.1 将定义的配置对象写出来

const config={ //定义配置对象token:'abc',appID:'wxb4fd0fa596cad699',appsecret:'49ebd101f6825cc60f5525975dda960f'}

// 1.1将微信加密签名的三个参数(timestamp,nonce,token)按照字典序排序组合在一起成一个数组

const arr = {timestamp,nonce,token};const arrSort=arr.sort(); //字典排序方法console.log(arrSort);

打开终端窗口安装sha1 再引入sha1模块

// 1.2将数组里面所有参数拼接成一个字符串,进行sha1加密

const str = arr.join(''); // 字符串拼接console.log(str);const arrStr = sha1(str); //进行加密console.log(arrStr);

// 1.3加密完成生成signature,与微信服务器发过来的进行比较

if(arrStr===signature){// 如果一样 返回echostr给微信服务器res.send(echostr);}else{// 如果不一样说明不是来自微信服务器 返回errorres.end('error');}

第一步完成效果

//引入express模块const express = require("express");//引入sha1模块const sha1 = require("sha1");//创建app应用对象const app = express();//验证服务器有效性// ngrok http 3000const config={ //定义配置对象token:'abc',appID:'wxb4fd0fa596cad699',appsecret:'49ebd101f6825cc60f5525975dda960f'}app.use((req,res,next) =>{// console.log(req.query);/*{signature: '964a71830c1839fd177b02b3cf9681f4611c3550', //微信的加密签名echostr: '8895758246790034999',//微信的随机字符串timestamp: '1654859299', //微信发送请求的时间戳nonce: '373056014' //微信的随机数字}*/const {signature,echostr,timestamp,nonce}=req.query; //解构赋值const {token}=config;// 1.验证消息是否来自微信服务器// 1.1将微信加密签名的三个参数(timestamp,nonce,token)按照字典序排序组合在一起成一个数组const arr = [timestamp,nonce,token];const arrSort=arr.sort(); //字典排序方法console.log(arrSort);// 1.2将数组里面所有参数拼接成一个字符串,进行sha1加密const str = arr.join(''); // 字符串拼接console.log(str);const arrStr = sha1(str); //进行加密console.log(arrStr);// 1.3加密完成生成signature,与微信服务器发过来的进行比较if(arrStr===signature){// 如果一样 返回echostr给微信服务器res.send(echostr);}else{// 如果不一样说明不是来自微信服务器 返回errorres.end('error');}})//监听端口号app.listen(3000,() => console.log('服务器启动成功'));

二.模块化封装处理

三.获取accessToken

// 整理思路://读取本地文件( readAccessToken)//-本地有文件// 判断它是否过期(isValidAccessToken)// -过期了// -重新请求获取access_ token(getAccessToken), 保存下来覆盖之前的文件(保证文件是唯一 -的) (saveAccess Token)// -没有过期// -直接使用// -本地没有文件// -发送请求获取access_ token(getAccessToken), 保存下来(本地文件) (saveAccessToken), 直接使用// get方式请求地址https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

安装request和request-promise-native库(只需要引入request-promise-native库)

1.1模拟测试

//引入configconst {appID,appsecret} = require('../config/config');//引入request-promise-native库const rp=require('request-promise-native');class Wechat{constructor() {}getAccessToken() { //获取access_token//定义请求地址const url = `https://api./cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;//发送请求rp({method: 'GET', url:url, json: true}).then(res => {//成功时的回调console.log(res);console.log('成功');}).catch(err => {//失败时的回调console.log(err);})}}//模拟测试const test = new Wechat();test.getAccessToken();

1.2getAccessToken完整设置方法

//引入configconst {appID,appsecret} = require('../config/config');//引入request-promise-native库const rp=require('request-promise-native');class Wechat{constructor() {}getAccessToken() { //获取access_token//定义请求地址const url = `https://api./cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;return new Promise((resolve,reject) =>{//发送请求rp({method: 'GET', url:url, json: true}).then(res => {//成功时的回调console.log(res);console.log('成功');// access_token: '57_ZQgtMRumuV5zTyEujjT8K86Xn7eds3CSRmKFEaSHQL7r2xHNpcDWb5-760xWom3He4e_SaPWO00UxE0AAjdmlpDv77P6FrPybFXWGaef4ovG3jZTW1fb// ZhulAWYG56Bou7Qoh7vLLkddAh3uUYPaABANRI',// expires_in: 7200过期时间//设置access_token的过期时间 -300是提前五分钟 单位是秒所以乘以1000res.expire_in = Date.now() + (res.expire_in - 300) * 1000;//将Promise的状态改为成功的状态resolve(res);}).catch(err => {//失败时的回调console.log(err);//将Promise的状态改为失败的状态reject('getAccessToken请求出现了问题'+err);})})}}//模拟测试const test = new Wechat();test.getAccessToken();

引入fs库模块

完整代码:

// 整理思路://读取本地文件( readAccessToken)//-本地有文件// 判断它是否过期(isValidAccessToken)// -过期了// -重新请求获取access_ token(getAccessToken), 保存下来覆盖之前的文件(保证文件是唯一 -的) (saveAccess Token)// -没有过期// -直接使用// -本地没有文件// -发送请求获取access_ token(getAccessToken), 保存下来(本地文件) (saveAccessToken), 直接使用// get方式请求地址https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET//引入request-promise-native库const rp=require('request-promise-native');//引入fs模块const {writeFile,readFile} = require('fs');//引入configconst {appID,appsecret} = require('../config/config');class Wechat{constructor() {}//获取access_tokengetAccessToken() {const url = `https://api./cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;return new Promise((resolve,reject) =>{//发送请求rp({method: 'GET', url:url, json: true}).then(res => {//成功时的回调console.log('获取access_token成功');// access_token: '57_ZQgtMRumuV5zTyEujjT8K86Xn7eds3CSRmKFEaSHQL7r2xHNpcDWb5-760xWom3He4e_SaPWO00UxE0AAjdmlpDv77P6FrPybFXWGaef4ovG3jZTW1fb// ZhulAWYG56Bou7Qoh7vLLkddAh3uUYPaABANRI',// expires_in: 7200过期时间//设置access_token的过期时间 -300是提前五分钟 单位是秒所以乘以1000res.expire_in = Date.now() + (res.expire_in - 300) * 1000;//将Promise的状态改为成功的状态resolve(res);}).catch(err => {//失败时的回调console.log(err);//将Promise的状态改为失败的状态reject('getAccessToken请求出现了问题'+err);})})}//保存accesstokensaveAcessToken(accessToken){return new Promise((resolve,reject) => {accessToken = JSON.stringify(accessToken) //将对象保存成JSON字符串//将access保存成一个文件writeFile("./accessToken",accessToken,err => {if(!err){console.log("文件保存成功");resolve();}else{console.log("文件保存失败")reject("getAccessToken方法出了问题"+err);}})})}//读取accesstokenreadAcessToken(){return new Promise((resolve,reject) => {readFile("./accessToken",(err,data) => {if(!err){console.log("文件读取成功");//将JSON字符串转化为js对象data = JSON.parse(data);resolve(data);}else{console.log("文件读取失败")reject("readAccessToken方法出了问题"+err);}})})}//检查accessToken是不是有效的isValidaccesstoken(data){//检查传入的参数是否有效if(!data && !data.accessToken && !data.expire_in){//代表access_token无效return false;}//检查access_token是否在有效期内// if(data.expire_in < Date.now()){////过期//return false;// }else{//return true;// }return data.expire_in > Date.now();}}//模拟测试const test = new Wechat();//读取本地文件( readAccessToken)//-本地有文件// 判断它是否过期(isValidAccessToken)// -过期了// -重新请求获取access_ token(getAccessToken), 保存下来覆盖之前的文件(保证文件是唯一 -的) (saveAccess Token)// -没有过期// -直接使用// -本地没有文件// -发送请求获取access_ token(getAccessToken), 保存下来(本地文件) (saveAccessToken), 直接使用// get方式请求地址https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRETnew Promise((resolve,reject) => {test.readAcessToken().then(res => {//本地有文件// 判断它是否过期(isValidAccessToken)if(test.isValidaccesstoken(res)){//有效的resolve(res);}else{//过期了test.getAccessToken().then(res => {// 保存下来(本地文件) (saveAccessToken), 直接使用test.saveAcessToken(res).then(() => {resolve(res);})})}}).catch(err => {//本地没有文件//-发送请求获取access_ token(getAccessToken)test.getAccessToken().then(res => {// 保存下来(本地文件) (saveAccessToken), 直接使用test.saveAcessToken(res).then(() => {resolve(res);})})})}).then(res => {console.log("获取成功")console.log(res);})

添加fetchAccessToken方法优化代码

// 整理思路://读取本地文件( readAccessToken)//-本地有文件// 判断它是否过期(isValidAccessToken)// -过期了// -重新请求获取access_ token(getAccessToken), 保存下来覆盖之前的文件(保证文件是唯一 -的) (saveAccess Token)// -没有过期// -直接使用// -本地没有文件// -发送请求获取access_ token(getAccessToken), 保存下来(本地文件) (saveAccessToken), 直接使用// get方式请求地址https://api./cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET//引入request-promise-native库const rp=require('request-promise-native');//引入fs模块const {writeFile,readFile} = require('fs');//引入configconst {appID,appsecret} = require('../config/config');class Wechat{constructor() {}//获取access_tokengetAccessToken() {const url = `https://api./cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;return new Promise((resolve,reject) =>{//发送请求rp({method: 'GET', url:url, json: true}).then(res => {//成功时的回调console.log('获取access_token成功');// access_token: '57_ZQgtMRumuV5zTyEujjT8K86Xn7eds3CSRmKFEaSHQL7r2xHNpcDWb5-760xWom3He4e_SaPWO00UxE0AAjdmlpDv77P6FrPybFXWGaef4ovG3jZTW1fb// ZhulAWYG56Bou7Qoh7vLLkddAh3uUYPaABANRI',// expires_in: 7200过期时间//设置access_token的过期时间 -300是提前五分钟 单位是秒所以乘以1000res.expire_in = Date.now() + (res.expire_in - 300) * 1000;//将Promise的状态改为成功的状态resolve(res);}).catch(err => {//失败时的回调console.log(err);//将Promise的状态改为失败的状态reject('getAccessToken请求出现了问题'+err);})})}//保存accesstokensaveAcessToken(accessToken){return new Promise((resolve,reject) => {accessToken = JSON.stringify(accessToken) //将对象保存成JSON字符串//将access保存成一个文件writeFile("./accessToken",accessToken,err => {if(!err){console.log("文件保存成功");resolve();}else{console.log("文件保存失败")reject("getAccessToken方法出了问题"+err);}})})}//读取accesstokenreadAcessToken(){return new Promise((resolve,reject) => {readFile("./accessToken",(err,data) => {if(!err){console.log("文件读取成功");//将JSON字符串转化为js对象data = JSON.parse(data);resolve(data);}else{console.log("文件读取失败")reject("readAccessToken方法出了问题"+err);}})})}//检查accessToken是不是有效的isValidAccesstoken(dta){//检查传入的参数是否有效if(!data && !data.accessToken && !data.expire_in){//代表access_token无效return false;}//检查access_token是否在有效期内// if(data.expire_in < Date.now()){////过期//return false;// }else{//return true;// }return data.expire_in > Date.now();}//获取没有过期的AccessTokenfetchAccessToken() {if(this.accesss_token && this.expires_in && this.isValidAccesstoken(this)) {//说明之前保存过access_token,并且他是有效的,直接使用return Promise.resolve({access_token:this.accesss_token,expires_in:this.expires_in})}return this.readAcessToken().then(async res => {//本地有文件// 判断它是否过期(isValidAccessToken)if (this.isValidAccesstoken(res)) {//有效的// resolve(res);return Promise.resolve(res);} else {//过期了//-发送请求获取access_ token(getAccessToken)const res = await this.getAccessToken()// 保存下来(本地文件) (saveAccessToken), 直接使用await this.saveAcessToken(res)//将请求回来的access_token返回出去// resolve(res);return Promise.resolve(res);}}).catch(async err => {//本地没有文件//-发送请求获取access_ token(getAccessToken)const res = await this.getAccessToken()// 保存下来(本地文件) (saveAccessToken), 直接使用await this.saveAcessToken(res)//将请求回来的access_token返回出去// resolve(res);return Promise.resolve(res);}).then(res => {//将access_token挂载到this上this.accesss_token = res.accesss_token;this.expires_in=res.expire_in;//返回res包装了一层promise对象(此对象为成功的状态)return Promise.resolve(res);})}}//模拟测试const test = new Wechat();new Promise((resolve,reject) => {test.readAcessToken().then(res => {//本地有文件// 判断它是否过期(isValidAccessToken)if(test.isValidaccesstoken(res)){//有效的resolve(res);}else{//过期了test.getAccessToken().then(res => {// 保存下来(本地文件) (saveAccessToken), 直接使用test.saveAcessToken(res).then(() => {resolve(res);})})}}).catch(err => {//本地没有文件//-发送请求获取access_ token(getAccessToken)test.getAccessToken().then(res => {// 保存下来(本地文件) (saveAccessToken), 直接使用test.saveAcessToken(res).then(() => {resolve(res);})})})}).then(res => {console.log("获取成功");console.log(res);})

四.获取用户发送的数据

4.1获取到用户发送的xml数据

新建tool工具包js文件

//工具包函数module.exports={getUserDataAsync(req){return new Promise((resolve,reject) => {let xmlData = '';req.on('data',data=>{//当流式数据传递过来时,会将数据注入回调函数中console.log(data);//读取的数据是buffer类型 需要转换成字符串xmlData += data.toString();}).on('end',() => {//数据接受完毕触发resolve(xmlData);})})}}

4.2完善auth模块

//验证服务器的有效性模块//引入sha1模块const sha1 = require("sha1");//引入tool模块const {getUserDataAsync} = require('../utils/tool');//引入config模块const config=require('../config/config');module.exports= () => {return async (req, res, next) => {const {signature, echostr, timestamp, nonce} = req.query; //解构赋值const {token} = config;const sha1Str = sha1([timestamp, nonce, token].sort().join(''));//微信服务器会发送两种类型的消息给开发服务器//1.get请求 - 验证服务器的有效性//2.post请求 - 微信服务器会将用户发送的数据以post请求的方式转发到开发者服务器上if (req.method === 'GET') {// 1.3加密完成生成signature,与微信服务器发过来的进行比较if (sha1Str === signature) {// 如果一样 返回echostr给微信服务器res.send(echostr);} else {// 如果不一样说明不是来自微信服务器 返回errorres.end('error');}} else if (req.method === 'POST') {//微信服务器会将用户发送的数据以post请求的方式转发到开发者服务器上if (sha1Str != signature) {//说明消息不是来自微信服务器res.end('error');}//接受请求体中的数据,流式数据const xmlData = await getUserDataAsync(req);console.log(xmlData);//如果开发者服务器没有返回响应给微信服务器,微信服务器会发送三次请求过来res.end('');} else {res.end('error');}}}

完整代码(进一步完善tool和auth模块)

//验证服务器的有效性模块//引入sha1模块const sha1 = require("sha1");//引入tool模块const {getUserDataAsync,parseXMLAsync,formatMessage} = require('../utils/tool');//引入config模块const config=require('../config/config');module.exports = () => {return async (req, res, next) => {const {signature, echostr, timestamp, nonce} = req.query; //解构赋值const {token} = config;const sha1Str = sha1([timestamp, nonce, token].sort().join(''));//微信服务器会发送两种类型的消息给开发服务器//1.get请求 - 验证服务器的有效性//2.post请求 - 微信服务器会将用户发送的数据以post请求的方式转发到开发者服务器上if (req.method === 'GET') {// 1.3加密完成生成signature,与微信服务器发过来的进行比较if (sha1Str === signature) {// 如果一样 返回echostr给微信服务器res.send(echostr);} else {// 如果不一样说明不是来自微信服务器 返回errorres.end('error');}} else if (req.method === 'POST') {//微信服务器会将用户发送的数据以post请求的方式转发到开发者服务器上if (sha1Str != signature) {//说明消息不是来自微信服务器res.end('error');}//接受请求体中的数据,流式数据const xmlData = await getUserDataAsync(req);// console.log(xmlData);// <xml><ToUserName><![CDATA[gh_7b0897f3d224]]></ToUserName> //开发者id//<FromUserName><![CDATA[o6i1N5jHaJKfi9tOCUYcUvq4ec0U]]></FromUserName> //用户open的id//<CreateTime>1655124555</CreateTime> // 发送的时间戳//<MsgType><![CDATA[text]]></MsgType>//发送的消息类型//<Content><![CDATA[233358]]></Content>//发送的消息内容//<MsgId>23695683538443223</MsgId>//消息id 微信默认保存3天// </xml>//将xml数据解析为js对象const jsData = await parseXMLAsync(xmlData);console.log(jsData);// xml: {//ToUserName: [ 'gh_7b0897f3d224' ],// FromUserName: [ 'o6i1N5jHaJKfi9tOCUYcUvq4ec0U' ],// CreateTime: [ '1655126378' ],// MsgType: [ 'text' ],// Content: [ '突突突' ],// MsgId: [ '23695710413710460' ]// }//格式化数据const message = formatMessage(jsData);console.log(message);// {//ToUserName: 'gh_7b0897f3d224',// FromUserName: 'o6i1N5jHaJKfi9tOCUYcUvq4ec0U',//CreateTime: '1656656271',//MsgType: 'text',//Content: '哈哈哈',//MsgId: '2371761341609'// }//如果开发者服务器没有返回响应给微信服务器,微信服务器会发送三次请求过来res.end('');} else {res.end('error');}}}

//工具包函数const {parseString} = require('xml2js'); // 将xml数据转化为js库 2原本是tomodule.exports={getUserDataAsync(req){return new Promise((resolve,reject) => {let xmlData = '';req.on('data',data => {//当流式数据传递过来时,会将数据注入回调函数中// console.log(data);//读取的数据是buffer类型 需要转换成字符串xmlData += data.toString();}).on('end',() => {//数据接受完毕触发resolve(xmlData);})})},parseXMLAsync(xmlData){return new Promise((resolve,reject) => {parseString (xmlData,{trim:true},(err,data) => {if(!err){resolve(data);}else{reject("parseXMLAsync方法出了问题"+err);}})})},formatMessage(jsData){let message = {};//获取xml对象jsData = jsData.xml;//判断数据是不是一个对象if(typeof jsData === 'object'){for (let key in jsData){//获取属性值let value = jsData[key];//过滤空的数据// if(Array.isArray(value) && value > 0){ 官方的过滤方法if(Array.isArray(value) && value!=' '){ //自己改写的//将合法的数据复制到message对象上message[key] = value[0];}}}return message;}}

五.简单的自动回复 根据文字回复文字

1.设置回复内容

let content = '你在说什么,我不知道';if(message.MsgType === 'text'){ //判断用户发送的消息类型if(message.Content === '1'){ //全匹配content='请不要扣1';}else if(message.Content.match('520')){ //半匹配content='520';}}

2.auth模块写入xml语句并 注释掉之前回复的空

let replyMessage='<xml>\n' +' <ToUserName><![CDATA['+message.FromUserName+']]></ToUserName>\n' + //用户id' <FromUserName><![CDATA['+message.ToUserName+']]></FromUserName>\n' + //开发者id' <CreateTime>'+Date.now()+'</CreateTime>\n' + //回复的时间戳' <MsgType><![CDATA[text]]></MsgType>\n' + //回复的类型' <Content><![CDATA['+content+']]></Content>\n' + //回复的内容'</xml>';//res.send(replyMessage);//如果开发者服务器没有返回响应给微信服务器,微信服务器会发送三次请求过来// res.end('');

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。