官网注册微信公众号
Express环境搭建。
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World.')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
因为微信消息的转发,需要服务器在外网环境下进行访问,而我们正常编写代码需要在本地环境,所以我们需要通过Natapp进行内网穿透(成本为每月9元)
Natapp是一款内网穿透工具,它可以将本地的网络服务映射到公网上,从而实现外网访问内网服务的功能。下面是使用Natapp进行内网穿透的步骤:
应用Express 应用程序生成器创建项目:
https://www.expressjs.com.cn/starter/generator.html
$ npx express-generator --ejs --view=ejs chatrobot
$ npm i
$ npm start
默认情况下微信的公众号是自动回复 我们需要将用户发送的消息 转到自己的服务器
微信第三方服务器配置
参见:https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html
Express 环境:
// /app.js
// ...
var chatrobotRouter = require('./routes/chatrobot');
// ...
app.use('/chatrobot', chatrobotRouter)
// ...
// /routes/chatrobot.js
const express = require('express');
const crypto = require('crypto')
const router = express.Router();
function checkSignature(req, res, next) {
// 定义 token,此 token 一定要与微信公众号 token 一致
const token = 'weixin'
// 获取来自微信服务器的信息
const { signature, echostr, timestamp, nonce } = req.query
// 将token、timestamp、nonce三个参数进行字典序排序,再拼接成一个字符串
const tmpStr = [token, timestamp, nonce].sort().join('')
// 将三个参数字符串拼接成一个字符串进行sha1加密
const mySignature = crypto.createHash('sha1').update(tmpStr).digest('hex')
// 获得加密后的字符串可与signature对比,标识该请求来源于微信
// 若确认此次GET请求来自微信服务器,请原样返回echostr参数内容
res.send(mySignature === signature ? echostr : 'error')
}
router.get('/', checkSignature)
module.exports = router;
消息接收,参见:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
消息回复,参见:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
完整代码:
1、安装中间件 express-xml-bodyparser
$ npm i express-xml-bodyparser
2、在app.js
文件中添加中间
// /app.js
// ...
var xmlparser = require('express-xml-bodyparser')
// ...
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(xmlparser())
// ...
3、创建视图
// /views/reply.ejs
// 注意这里fromusername 和 tousername 是相反的。
<xml>
<ToUserName>
<![CDATA[<%= fromusername %>]]>
</ToUserName>
<FromUserName>
<![CDATA[<%= tousername %>]]>
</FromUserName>
<CreateTime>
<%= createtime %>
</CreateTime>
<MsgType>
<![CDATA[text]]>
</MsgType>
<Content>
<![CDATA[<%= content %>]]>
</Content>
</xml>
4、添加核心代码
// /routes/chatrobot.js
// ...
function formatMsg(msg) {
const msgXml = msg.xml
const msgArray = Object.keys(msgXml)
return msgArray.reduce((obj, key) => {
obj[key] = msgXml[key][0]
return obj
}, {})
}
function messageController(req, res, next) {
// 接收到微信方发来的消息并处理
const msg = formatMsg(req.body)
// 回复信息
const {
tousername,
fromusername
} = msg
msg['createtime'] = Math.floor((new Date().getTime()) / 1000)
msg['content'] = '你好呀 ☕️'
res.set('Content-Type', 'text/xml')
res.render('reply', msg)
}
// ...
// 消息接收与回复
router.post('/', messageController)
// ...