后端接入微信公众号 |
您所在的位置:网站首页 › 微信公众号平台自动回复功能 › 后端接入微信公众号 |
目录 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 |