后端接入微信公众号

您所在的位置:网站首页 微信公众号平台自动回复功能 后端接入微信公众号

后端接入微信公众号

2024-07-11 19:05| 来源: 网络整理| 查看: 265

目录

1、配置服务器并填写相关信息

1-1)解决80端口正在被nginx服务的端口占用情况,完成服务端验证

2、接收用户的消息

2-1)在express项目中新增一个监听 post 请求的方法来获取用户消息

2-2)使用 xmljson 解析和处理用户消息

3、回复用户的消息-文本回复

4、回复用户的内容-图片

4-1)到公众号的素材库中上传图片:

4-2) 获取 access-token

4-3)获取公众号中的图片资源(永久素材列表)

4-4)返回一个图片给用户作为回复

1、配置服务器并填写相关信息

        接入微信公众号的第一步,首先要登录微信公众平台官网,在公众平台官网左侧导航栏的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey。

        其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

         当填写好以上的信息后,微信服务器将发送GET请求到填写的服务器地址URL上,请求会携带以下的参数:

        开发者通过下方的检验方式对请求进行校验。若确认此次GET请求来自微信服务器,则原样返回echostr参数内容,便接入成功,否则接入失败。加密/校验流程如下:

        1)将token(就是我们设置的token)、timestamp、nonce三个参数进行字典序排序;

        2)将三个参数字符串拼接成一个字符串进行sha1加密;

        3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信;

 

1-1)解决80端口正在被nginx服务的端口占用情况,完成服务端验证

        根据官方文档给出的校验方法和示例,完成 express 的校验服务,并进行部署:

const express = require('express'); const crypto = require('crypto'); app.get('/wechat-test', (req, res)=>{ const token = 'xxx_xxx'; let {signature, timestamp, nonce, echostr} = req.query; let arr = [nonce, timestamp, token]; arr.sort(); // 排序 let str = arr.join(''); // 转成字符串 let shanum = crypto.createHash('sha1'); let mysignature = shanum.update(str).digest('hex'); let result = (mysignature === signature); if(result){ res.send(echostr); }else{ res.send(); } }); app.listen(80, ()=>{ console.log('80 listening'); })

        填写 http 协议,80 端口的服务器地址。 将上面的 express 服务端程序部署到服务器中,试运行:

cd 项目部署的目录下 pm2 start index.js --name wechat-test

        发现报错:EADDRINUSE,即该80端口已经被占用。查看80端口的占用情况:

sudo lsof -i :80

         发现80端口nginx正在监听并提供服务:

         为了不破坏主页面原有的服务,选择使用请求转发的方式,将express项目的监听端口设置为3001,并在控制台安全组中开放该端口,在nginx中配置将80的访问转发到3001端口:

server{ listen 80; ...... # 请求转发到本地的3001端口进行处理 location /wechat-test { proxy_pass http://localhost:3001; } }

        请求 http://www.example.cn/wechat-test 将转发到 http://www.example.cn:3001/wechat-test。

        重新在服务器中运行express服务,运行成功后在微信提交服务器配置,微信会get请求到目标URL进行验证,验证成功后即显示接入成功,选择启动服务器配置:

        

 

2、接收用户的消息

        当普通微信用户向公众账号发消息时,微信服务器将发送一个post请求到我们填写的URL地址中,并携带 XML 数据(包含用户输入的消息和一些其他的信息)。

        a. 文本消息XML:

1348831860 1234567890123456 xxxx xxxx

        其中:

toUserName开发者微信号FromUserName发送方账号(openid)CreateTime消息创建的时间MsgType消息的类型,如果是文本即为textContent文本消息的内容

        b.图片消息:

1348831860 1234567890123456 xxxx xxxx

        其中:

PicUrl由系统生成的图片链接MediaId图片消息媒体id,可以调用获取临时素材接口拉取数据

2-1)在express项目中新增一个监听 post 请求的方法来获取用户消息

        直接添加到原来的项目文件中即可。

// 监听的路径要和填写的URL路径一致 app.post('/wechat-test',(req, res)=>{ // 用来保存xml数据结果 let data = ''; // 接收xml数据 req.on('data',(chunk)=>{ data += chunk; }) req.on('err',(err)=>{ res.send(''); }) req.on('end',()=>{ // 数据接收完毕 console.log('数据接收完毕\n', data); res.send(); }) })

        在公众号中发送消息:1234。使用 pm2 logs 查看运行日志,查看项目的输出内容:

         此时在微信公众号中看不到任何来自公众号的回应。

2-2)使用 xmljson 解析和处理用户消息

         下载 xmljson :npm i xmljson;

        基本使用,将 xml 内容转换成对象的形式:

// 直接引入一个方法,将xml内容转换成对象 const toJson = require('xmljson').to_json; app.post('/wechat-test',(req, res)=>{ let data = ''; req.on('data', chunk=>{ data += chunk; }) req.on('err',(err)=>{ res.send(''); }) req.on('end',()=>{ console.log('接收完毕:\n',data,'\n\n'); toJson(data, (err, xmlObj)=>{ if(err){ console.log('转换错误'); res.send('处理错误'); }else{ console.log('转换完成:\n', xmlObj); res.send(''); } }) }) })

        在公众号中发送消息:你好。

 

         转换后的对象又包含一个 xml 对象,该对象中的内容即为 “xml标签名:标签体内容”的形式,我们要得到用户的消息,只需要 xmlObj.xml.Content 即可。

 

3、回复用户的消息-文本回复

        回复的内容也需要是XML格式的,如:

         其中,Content 中的内容为回复的消息内容。ToUSerName 和 FromUserName 都是必须携带的内容。

        下面这个示例将回复用户:`你好,${用户发送过来的消息}`;

app.post('/wechat-test',(req, res)=>{ let data = ''; req.on('data',(chunk)=>{ data += chunk; }).on('end',()=>{ toJson(data, (err, obj)=>{ if(err){ console.log('错误:',new Date().toLocaleString()); res.send(` ${new Date().getTime()} `) }else{ let ans = ` ${new Date().getTime()} ` res.send(ans); } }) }) })

         在公众号发送消息,查看回复:

         

        注意,服务器需要在5s内做出回复,否则微信服务器将在5s后断掉连接,并重新发送请求,总共会发送3次请求,若服务器都没能按时回复,则会按超时处理。

        如果服务器无法保证在5秒内做出回复,可以考虑直接回复success,或返回一个空字符串(则什么都不回复)。

        如果服务器没有在5s内返回数据,或返回的数据不是xml格式的,微信都会在公众号对话中向用户发送系统提示消息“该公众号暂时无法提供服务,请稍后再试”。

 

4、回复用户的内容-图片  4-1)到公众号的素材库中上传图片:

 

4-2) 获取 access-token

         获取素材库中的素材需要使用到 access-token ,可以发送以下的请求来后期 access-token:

GET  https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

        如果要获取的是 access-token 则 grant_type 填写 client_credential;

        appid 和 secret 可以到公众号-基本配置中配置并获取:

         请求成功后,在res.data 中会有以下的信息,其中expires_in 是有效时间s:

参考:微信开放文档

         

4-3)获取公众号中的图片资源(永久素材列表)

         获取永久素材列表可以发送以下请求:

post https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN access-token 即刚刚获取到的access_token 需要携带的data:{ "type":"image", // 表示请求图片资源,还可以是视频(video)、语音 (voice)、图文(news) "offset":0, // 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回 "count":5, // 表示返回的数量在 1-n 之间,当前为 1-5 }

        一个示例:

// 处理图片类型的消息-返回固定的图片 function dealImgMsg(xmlObj, res){ // 先获取 access_token axios.get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${YOU_APPID}&secret=${YOU_SECRET}').then((result)=>{ // 提取出来的 access_token let access_token = result.data.access_token; reqData = { 'type':'image', 'offset':0, 'count':5 } // 再请求获取图片类型的资源 axios.post(`https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=${access_token}`,reqData).then(result1=>{ let data = result1.data; // 图片资源存放在data.item 中 ,查看结果 console.log(data.item, data.item[0]); res.send(); }) }) }

        输出的内容(media_id 即我们需要使用到的内容):

参考:微信开放文档

4-4)返回一个图片给用户作为回复 const axios = require('axios'); app.post('/wechat-test',(req, res)=>{ let data = ''; req.on('data',(chunk)=>{ data += chunk; }).on('end',()=>{ toJson(data, (err, result)=>{ let xmlObj = result.xml; if(err){ console.log('错误:',new Date().toLocaleString()); res.send() }else{ switch (xmlObj.MsgType) { case 'image': dealImgMsg(xmlObj, res); break; case 'text': dealTextMsg(xmlObj, res); break; default: res.send() } } }) }) }) // 处理图片类型的消息-返回固定的图片 function dealImgMsg(xmlObj, res){ axios.get(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${YOU_APPID}&secret=${YOU_SECRET}`).then((result)=>{ let access_token = result.data.access_token; reqData = { 'type':'image', 'offset':0, 'count':5 } axios.post(`https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=${access_token}`,reqData).then(result1=>{ let data = result1.data; let resXML = ` ${new Date().getTime()} ` res.send(resXML); }) }) } // 处理文字类型的消息-返回用户发送来的消息加自定义的内容 function dealTextMsg(xmlObj, res){ let resXML = ` ${new Date().getTime()} `; res.send(resXML); }

 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3