初衷 最近在弄个人公众号,也会发表一些自己的技术实现,同时为了要加粉,所以加了一个回复关键字获取demo的功能,可是每次设置关键字都要在微信公众平台设置,比较繁琐,于是想到直接使用后端控制,然而,受限于自身后端实力,要搭建一个完整的系统实在有些为难,所以才去了折中的办法。
面向对象
后端不熟悉,但有基本的编程思维;
稍微了解运营基础(可以参考我的另外一篇文章CentOS下从零开始部署自己的博客 );
功能简单,没有复杂场景,比较适合个人。
开发过程 工具 必须
软件推荐
ssh工具:Mobaxterm(windows)、nuoshell(mac) ——都是免费的,linux 就直接用命令行好了
nginx:其它工具也行,不用代理apache也可以
pm2: 便于管理express应用
安装工具
安装node和nginx
往期文章已详细叙述,不在赘述CentOS下从零开始部署自己的博客
npm命令,本人皆使用的是淘宝镜像,用cnpm命令速度将快速很多
安装express脚手架和pm2
1 2 npm install express-generator -g npm install pm2 -g
推荐直接安装express脚手架,这样路由什么的都已经配好了,方便拿来即用,当然想自定义的,可以只安装express。
创建微信工程,并安装依赖
1 2 3 express -e wechat cd wechat npm install
申请微信参数 我们可以先在测试环境使用,在微信公众平台接口测试帐号申请 页面,创建基本参数,并记住token参数。
代码编写 功能开发
该步骤需要安装crypto
按照文档描述,将字段排序并加密后与签名比对,代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const crypto = require('crypto'); router.get('/', function (req, res, next) { const signature = req.query.signature; const timestamp = req.query.timestamp; const nonce = req.query.nonce; const echostr = req.query.echostr; // 1. 将token、timestamp、nonce三个参数进行字典序排序 let array = new Array('微信后台设置的token', timestamp, nonce); array.sort(); let str = array.toString().replace(/,/g, ""); // 2. 将排序后的字符串进行sha1加密 let sha1Code = crypto.createHash("sha1"); let code = sha1Code.update(str, 'utf-8').digest("hex"); // 3. 与signature对比,如果匹配表示数据来自微信 if (code === signature) { res.send(echostr) } else { res.send("error"); } });
回复功能
因为与微信的交互都是xml格式,所以我们还要安装一个xml解析库
解析接受的消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const parseString = require('xml2js').parseString; router.post("/", (req, res) => { var buffer = []; req.on('data', function (data) { buffer.push(data); }); req.on('end', function () { var msgXml = Buffer.concat(buffer).toString('utf-8'); parseString(msgXml, { explicitArray: false }, (err, result) => { if (err) { throw err; } result = result.xml; var toUser = result.ToUserName; var fromUser = result.FromUserName; if (result.MsgType === "text") { // 文本消息 } else if (result.MsgType === "image") { // 图片消息 } else if ('event' === result.MsgType) { if ('subscribe' === result.Event) { // 被关注 } } }) }) });
回复文本消息
1 2 3 4 5 6 let str = `<xml><ToUserName><![CDATA[${fromUser}]]> </ToUserName><FromUserName><![CDATA[${toUser}]]></FromUserName> <CreateTime>${new Date().getTime()}</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你回复的文本内容]]></Content></xml>`; res.send(str);
菜单功能
菜单功能仅对认证的公众号开放,因本人公众号并未认证,所以在正式号上,没发实现,但测试是可以的。
1 2 3 4 5 6 7 axios.post(`https://api.weixin.qq.com/cgi-bin/menu/create?access_token=获取到的access_token`, '菜单内容').then((response) => { if (response.data.errcode == 0) { // 成功 } }).catch((error) => { // 失败 });
不用数据库实现各功能的动态更新 画重点,这是最主要的地方
不用数据库,我们直接使用json配置文件,模拟数据库,该怎么做呢?
fs库给我们提供了一个api
1 2 3 4 5 6 /** * Watch for changes on `filename`. The callback `listener` will be called each time the file is accessed. * @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol. * URL support is _experimental_. */ export function watchFile(filename: PathLike, listener: (curr: Stats, prev: Stats) => void): void;
所以,我们在node启动时,注册一个监听,就可以实时更新数据了,都不需要重启服务器,是不是很简单。
代理 因为微信仅支持80/443端口,所以我们需要使用nginx代理一下,当然端口没有占用,你直接将node运行在这个端口上也没问题。 比如本人是开启的443端口,则代理配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 server { listen 443 ssl; server_name 代理域名; ssl_certificate 签名文件; ssl_certificate_key 签名文件; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Nginx-Proxy true; proxy_set_header Connection ""; // 这里填写实际的地址和端口 proxy_pass http://127.0.0.1:3000; proxy_redirect default; #root html; #index index.html index.htm; } }
运行 至此,所有的开发完成了,我们如果想测试效果,可以
如果我们发布,自然不会一直挂在终端上,所以我们用pm2命令
更多命令,可以自行搜索。
最后 如需获取完整demo,可以关注公众号[奶爸程序猿]回复”wxexpress”获取。
原文链接: https://blog.xyzzlky.cn/posts/2f4df446/
版权声明: 转载请注明出处.