目录

整体思维导图
<https://blog.csdn.net/XZZ2222/article/details/81220739#%E6%95%B4%E4%BD%93%E6%80%9D%E8%B7%AF>

详细步骤
<https://blog.csdn.net/XZZ2222/article/details/81220739#%E8%AF%A6%E7%BB%86%E6%AD%A5%E9%AA%A4>

1、申请公众号,完成微信公众平台接口测试申请。
<https://blog.csdn.net/XZZ2222/article/details/81220739#1%E3%80%81%E7%94%B3%E8%AF%B7%E5%85%AC%E4%BC%97%E5%8F%B7%EF%BC%8C%E5%AE%8C%E6%88%90%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%B9%B3%E5%8F%B0%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95%E7%94%B3%E8%AF%B7%E3%80%82>

2、填写服务器配置
<https://blog.csdn.net/XZZ2222/article/details/81220739#2%E3%80%81%E5%A1%AB%E5%86%99%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AE>

3、验证服务器的有效性
<https://blog.csdn.net/XZZ2222/article/details/81220739#3%E3%80%81%E9%AA%8C%E8%AF%81%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E6%9C%89%E6%95%88%E6%80%A7>

3、模块化
<https://blog.csdn.net/XZZ2222/article/details/81220739#3%E3%80%81%E6%A8%A1%E5%9D%97%E5%8C%96>

4、获取access_token
<https://blog.csdn.net/XZZ2222/article/details/81220739#4%E3%80%81%E8%8E%B7%E5%8F%96access_token>

5、获取用户消息
<https://blog.csdn.net/XZZ2222/article/details/81220739#5%E3%80%81%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E6%B6%88%E6%81%AF>

6、处理用户发送过来的信息
<https://blog.csdn.net/XZZ2222/article/details/81220739#6%E3%80%81%E5%A4%84%E7%90%86%E7%94%A8%E6%88%B7%E5%8F%91%E9%80%81%E8%BF%87%E6%9D%A5%E7%9A%84%E4%BF%A1%E6%81%AF>

7、通过解析用户发送来的消息,进行相应的回复
<https://blog.csdn.net/XZZ2222/article/details/81220739#7%E3%80%81%E9%80%9A%E8%BF%87%E8%A7%A3%E6%9E%90%E7%94%A8%E6%88%B7%E5%8F%91%E9%80%81%E6%9D%A5%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E8%BF%9B%E8%A1%8C%E7%9B%B8%E5%BA%94%E7%9A%84%E5%9B%9E%E5%A4%8D>

 

整体思维导图



详细步骤

1、申请公众号,完成微信公众平台接口测试申请。

2、填写服务器配置

在本地搭建好服务器,并利用ngrok输入指令ngrok http
3000(相应的端口号)生成对应的IP,将本地生成的服务器端口号生成对应的外网跨域访问的网址。在服务器中配置相应的信息。 

*
配置信息的代码实现
const config = { appID:"wx6077e5089a73e15d",
appsecret:"4408047fc4a1337366a94bdaf63cee57", token:"lemonclass0412" }
说明:appID 是第三方用户唯一凭证

appsecret 是 第三方用户唯一凭证密钥

3、验证服务器的有效性

* 首先将参数签名加密的三个参数timestamp、nonce、token按照字典序进行排序
* 将排序后的参数拼接成一个字符串,进行sha1加密
* 将加密后的字符串与signature进行对比
如果匹配,说明验证成功的,返回echostr给微信服务器. 如果不匹配,说明验证失败的,返回''给微信服务器

*
代码实现
const {signature,echostr,timestamp,nonce} =req.query;
//1、将timestamp、nonce、token排序、加密 const sha1Str =
sha1([timestamp,nonce,token].sort().join('')) //2、匹配,返回echostr,不匹配,返回''
if(sha1Str === signature)res.send(echostr) else res.send("");
3、模块化

1、暴露模块--->module.exports

2、暴露的模块,要有返回值,利用return

3、异步的函数,要结合async...await使用



4、获取access_token

access_token特点:

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

获取方法:
1、上来判断本地有没有access_token (readAccessToken) 如果有
判断access_token有无过期,(isValidAccessToken) 如果没有过期,直接使用
如果过期了,再次请求获取access_token(getAccessToken),保存下来(saveAccessToken) 如果没有
发送请求获取access_token(getAccessToken),保存下来(至少1小时55分钟)(saveAccessToken)
2、官方文档:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
<https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183>

思路实现

将四个方法定义成一个类Wechat,然后通过构造实例对象,调用Wechat的方法。


const wechatAPI = new Wechat;
代码实现

* getAccessToken函数
* 注意: 在node服务器中发送请求,不能利用ajax,所以我们借助两个包---request、request-promise-native来完成。
* npm install --save request
* npm install --save request-promise-native
* 引用 const rq = require("request-promise-native"); (注意下载两个,但是只引用一个)
* 说明:rq的返回值是一个promise对象,可以调用.then,catch方法。
* 由于方法是异步的,我们借助new Promise((resolve, reject) => {}来获取返回值 getAccessToken() {
//https请求方式: GET
//https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
const url =
`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appID}&secret=${appsecret}`;
return new Promise((resolve, reject) => { // rq的本质是一个promise对象 rq({method:
"GET", url, json: true}) .then(res => { //相应的数据 console.log(res); //设置凭据的过期时间
res.expires_in = Date.now() + (res.expires_in - 300) * 1000; resolve(res); })
.catch(err =>reject("getAccessToken方法出了错误:"+err)); }) }
* saveAccessToken函数
* 说明:利用文件的简单写入来保存获取到的数据 const {writeFile,readFile} = require("fs");
saveAccessToken(data){ return new Promise((resolve, reject) => {
//微信会返回下述JSON数据包给公众号,要转一下js格式 data = JSON.stringify(data);
//为了方便读取,将获取到的数据保存到accessToken.txt文件中 writeFile("accessToken.txt",data,err=>{
if(!err){ resolve(data) }else{ reject("saveAccessToken方法出错了"+err) } }) }) }
*
readAccessToken函数

* 说明:利用文件的简单读取来读取相应的数据 const {readFile} = require("fs");
*
fs.readFile语法:

fs.readFile('accessToken.txt', (err, data) => { if (!err) console.log(data);
else throw err; });
readAccessToken(){ return new Promise((resolve, reject) => {
readFile("accessToken.txt",(err,data)=>{ if (!err){ //返回时将读取到的数据再转化为json数据
resolve(JSON.parse(data.toString())) } else{ reject("readAccessToken方法出错了"+err)
} }) }) }
*
isValidAccessToken函数
isValidAccessToken(data){ //优化:如果没有以上的属性,直接返回,不用再走下面逻辑 if(!data ||
!data.access_token || !data.expires_in) return false;
//如果没有过期,返回true,过期了,返回false return Date.now()< data.expires_in; }
5、获取用户消息

*
fetchAccessToken函数:获取accessToken,定义再wechat类中
fetchAccessToken(){ //性能优化 if(this.access_token && this.expires_in &&
this.isValidAccessToken(data)){ //如果没有过期,且有这几个属性,直接返回出去,不用重新获取 return
Promise.resolve({access_token:this.access_token,expires_in:this.expires_in}); }
return this.readAccessToken() .then(async res=>{ //如果有
if(this.isValidAccessToken(res)){ //没有过期 return Promise.resolve(res) }else{
//过期了 const data = await this.getAccessToken(); await
this.saveAccessToken(data); return Promise.resolve(data) } }) .catch(async
()=>{ //如果 没有 const data = this.getAccessToken(); await
this.saveAccessToken(data); return Promise.resolve(data) })
/*以上返回的结果为一个promise对象,但是返回的结果都是成功的回调。这样还可以利用.then方法,
这一步调用.then方法是为了优化----将两个属性挂载再this的这个类上,外界就可以直接进行判断,见上面 性能优化 部分*/ .then(res=>{
//将access_token和expires_in挂载到this上 this.access_token = res.access_token;
this.expires_in = res.expires_in; //给函数一个整体的返回值 return Promise.resolve(res); })
}
*
调用
(async ()=>{ const wechatAPI = new Wechat; const data = await
wechatAPI.fetchAccessToken(); })();
6、处理用户发送过来的信息

说明:

1、微信会发送两个消息:
GET:验证服务器的有消息(我们在服务器验证模块中已经验证过了) POST:接受用户发送过来的消息(以下代码处理POST请求): else
if(req.method === "POST"){ console.log(req.query);}
2、req.query返回出来的数据是一个xml格式的:
<xml> <ToUserName><![CDATA[gh_406d257c2cc2]]></ToUserName>
<FromUserName><![CDATA[owOA61F8J8xzZv1EpmUcsAcalXPI]]></FromUserName>
<CreateTime>1532582999</CreateTime> <MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[2]]></Content> <MsgId>6582393859576522806</MsgId> </xml>
3、所以要将其转化为一个js格式的对象。转化步骤:

*
先利用xml2js将 xml ---带有xml属性的对象

*
xml2js转化语法:
var parseString = require('xml2js').parseString; var xml = "<root>Hello
xml2js!</root>" parseString(xml, function (err, result) { console.dir(result);
});
* 引入:const {parseString} = require("xml2js");
*
将xml属性的对象遍历,转化为js一般对象

4、定义三个专门用来转化的方法:

* getuserDataAsyc() //获取用户发送来的信息
* parserXMLDataAsyc() //xml--->带有xml属性的对象
* formatData() //带有xml属性的对象--->js一般对象的形式
图示: 

代码实现

1、getuserDataAsyc()
getuserDataAsyc(req) { return new Promise((resolve, reject) => { let userData
= ''; req //传送数据,不断累加 .on('data', data => { userData += data; })
//数据传送完毕后,将结果返回出去 .on('end', () => { resolve(userData); }) }) }
说明:此时userData的返回值形式为:xml格式,见上。

2、 parserXMLDataAsyc()

前提:引入const {parseString} = require("xml2js")
parserXMLDataAsyc(xmlData) { return new Promise((resolve, reject) => {
parseString(xmlData, {trim: true}, function (err, result) { if (!err) {
resolve(result); } else { reject("parserXMLData方法出错了" + err); } }); }) }
说明:此时result返回的数据格式:
{ xml: { ToUserName: [ 'gh_406d257c2cc2' ], FromUserName: [
'owOA61F8J8xzZv1EpmUcsAcalXPI' ], CreateTime: [ '1532519920' ], MsgType: [
'text' ], Content: [ '2222' ], MsgId: [ '6582122937334454364' ] } }
3、formatData()
formatData(newData) { const jsData = newData.xml; for (let item in jsData) {
let value = jsData[item]; //防止不是数组获取非法数据 if(Array.isArray(value) &&
value.length) jsData[item] = value[0]; } return jsData; }
说明:jsData数据格式:
{ ToUserName: 'gh_406d257c2cc2', FromUserName: 'owOA61F8J8xzZv1EpmUcsAcalXPI',
CreateTime: '1532583006', MsgType: 'text', Content: '2', MsgId:
'6582393889641293880' }
7、通过解析用户发送来的消息,进行相应的回复

说明:

1、一旦遇到以下情况,微信都会在公众号会话中,
向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”: 1、开发者在5秒内未回复任何内容 2、开发者回复了异常数据,比如JSON数据等
2、通过if判断MsgType类型,利用Content进行内容回复
const replyMessage = '<xml>' + '<ToUserName><![CDATA['+userDate.FromUserName
+']]></ToUserName> ' + '<FromUserName><![CDATA['+
userDate.ToUserName+']]></FromUserName> ' +
'<CreateTime>'+Date.now()+'</CreateTime> ' +
'<MsgType><![CDATA[text]]></MsgType>' + ' <Content><![CDATA['+
content+']]></Content> ' + '</xml>'; //返回相应给服务器 res.send(replyMessage);

友情链接
ioDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信