成 都 狮 龙 书 廊 科 技 有 限 责 任 公 司
Chengdu Shilong Pearson Education technology Limited Liability Technology Group Co., Ltd.
头条号网站验证文件
客服电话:13904310313
公司总机:028-67876373
钉钉客服:17684321066
备案电话:15680712313
商标注册服务电话:15210354365
公安部备案号:22010602000144
google-site-verification: googlea5d4809e7c237a00.html
如何接收企业微信回调
¥100
在上一节教程中,我们创建了一个第三方应用,得到了对应的 suite_id/ suite_secret 信息,但是并没有对数据回调和接口回调进行响应,网页提示验证不通过。
在本节课程中,我们将完善服务端的逻辑,接收企业微信的回调,使回调 URL 的配置能够通过验证。
通过本节教程,开发者将了解:
在开始本教程内容前,开发者需要做如下准备:
本节教程将以 Node.js 作为代码语言示例,讲解对应的操作流程。
在配置应用的开发信息时,我们已经知道了第三方应用的回调配置有数据回调和指令回调两种。
数据回调,用于接收托管企业微信应用的用户消息、进入应用事件、通讯录变更事件。
指令回调,用于接收应用授权变更事件(应用添加、删除、修改)以及ticket参数,ticket说明详API接口说明。
对于数据回调和指令回调的两个 URL ,在服务端的实现时,都必须同时支持 HttpGet 以及 HttpPost两种能力。
仅用于在应用创建配置应用信息时的验证,企业微信服务端会向回调URL发起一个 Get 请求,当该回调URL按照约定进行了响应后,表明第三方服务具备解析企业微信推送消息的能力。
用于实际的业务请求,比如应用菜单的点击事件,用户消息等。当有回调的行为发生时,企业微信服务端会向该回调URL发起一个 Post 请求,同时数据会已加密的形式推送到该回调 URL,第三方服务商接受信息、解密信息,处理业务逻辑,并且按照约定进行响应即可。
回调服务的 URL 是一个公网的 URL,如果在实际进行应用开发时,代码和服务是部署在本地机器的话,那么需要搭建一个内网穿透服务,要让企业微信服务器发来的数据回调和指令回调,能够到达本地服务。
目前社区有许多较成熟的内网穿透解决方案,开发者可根据实际需要进行选择。企业微信开发者中心也会在近期的版本中,推出企业微信开发者官方的内网穿透工具。
根据创建第三方应用时填写的回调URL,假设为 http://myapp.com/callback/command
,我们将来实现这个URL的 get 请求路由,并且按照要求响应。
数据回调URL 和 指令回调URL 均需要支持 HttpGet 形式的请求回调。
const express = require('express');const router = express.Router();// get方式 用于验证router.get('/callback/data', validateCallback);router.get('/callback/command', validateCallback);
企业微信回调服务会通过 HttpGet 的形式请求回调 URL,并将 msg_signature、timestamp、nonce、echostr 以 query 参数的形式传递过来。我们在回调URL的逻辑中,解析出这些参数。
// 从 query 中获取相关参数const { msg_signature, timestamp, nonce, echostr } = req.query;
根据在上一步获取的参数timestamp、nonce、echostr,连同 Token一起,使用加解密库的加密函数重新加密计算签名。
// 引入官方的加解密库const crypto = require('@wecom/crypto');// 在应用详情页找到对应的tokenconst token = '';// 重新计算签名const signature = crypto.getSignature(token, timestamp, nonce, echostr);console.log('signature', signature);
通过 EncodingAESKey 和解析出来的 echostr 作为参数,使用加解密库的解密函数,解密出对应的 message,并立即以明文的形式直接返回。
// 校验签名是否正确if (signature === msg_signature) {console.info('签名验证成功')// 在应用详情页找到对应的EncodingAESKeyconst aeskey = '';// 如果签名校验正确,解密 messageconst { message } = crypto.decrypt(aeskey, echostr);console.log('message', message);// 返回 message 信息res.send(message);}
到这里,我们已经完成了回调URL的 get 实现,在【应用详情】-【回调配置】重新点击编辑保存,便可以重新触发指令回调URL和数据回调URL的验证,确保网页不再提示“服务商未响应请求,将无法获取用户事件回调”。
想要了解更多 Get 回调的实现,可以参考 支持http-get请求验证url有效性。
数据回调URL 和 指令回调URL 均需要支持 HttpPost 形式的请求回调。
const express = require('express');const router = express.Router();// post方式 用于授权、业务数据回调router.post('/callback/command', function (req, res, next) {});
企业微信回调服务会通过 HttpPost 的形式请求该回调URL,并将 msg_signature、timestamp、nonce 以 query 参数的形式传递过来,像 HttpGet 形式一样,需要先对参数进行解析,并且校验签名有效。
获取的参数 timestamp、nonce、echostr,连同 Token一起,使用加解密库的加密函数重新加密计算签名。
// 引入官方的加解密库const crypto = require('@wecom/crypto');// 从 query 中获取相关参数const { msg_signature, timestamp, nonce } = req.query;// 在应用详情页找到对应的tokenconst token = '';// 重新计算签名const signature = crypto.getSignature(token, timestamp, nonce, echostr);console.log('signature', signature);
在 HttpPost 回调中,密文内容是以 XML 字符串的形式放在 RawBody 中,通过对该 XML 字符的解析读取出对应的加密消息 Encrypt。
通过 EncodingAESKey 和加密消息 Encrypt 作为参数,使用加解密库的解密函数,解密出对应的 message。
而 message 仍然是一个 XML 字符串格式,再次对该 XML 解析,便可以得到本次 HttpPost 回调实际的数据信息。
// 解析 xml 的字符串内容let wholeXML = await getRawBody(req, {length: req.headers['content-length'],limit: '1mb',encoding: 'utf-8'});// 将 xml 解析成 jsonlet formatJson = await parseXML(wholeXML);// 得到加密消息体let encrypt = formatJson.Encrypt;// 在应用详情页找到对应的EncodingAESKeyconst aeskey = '';// 将加密消息体进行解密,解密后仍旧是 xml 字符串let messageXML = crypto.decrypt(aeskey, encrypt);// 把解密后 xml 消息体字符串,解析成 jsonlet callbackDataBody = await parseXML(messageXML.message);console.log('CallbackData', callbackDataBody);
不同的业务回调要求返回不同内容,在本节中我们直接返回 success
字符串即可。
// 响应返回res.send('success');
想要了解企业微信回调设置的更详细信息,可以参考文档 回调配置。
到这里,我们已经完成了第三方应用的 HttpPost 回调配置逻辑框架,在下一节教程,我们就可以利用这个指令回调实现 suite_ticket 的接收,从而获得 suite_access_token。