# 消息推送开发手册
消息推送是开放平台推出的一种主动推送服务,基于该推送服务,开发者及时获取开放平台相关信息,无需调用 API。
总数据链路如图所示:
# 1、消息推送服务器配置
消息推送服务于小程序、公众号、小游戏、视频号小店、第三方平台,这里介绍在网站应用的配置。
# 1.1 填写相关信息
登录 OPEN 平台,在「管理中心」-「网站应用」-「消息推送」中,需填写以下信息:
- URL 服务器地址:开发者用来接收微信消息和事件的接口 URL,必须以 http:// 或 https:// 开头,分别支持 80 端口和 443 端口。
- Token 令牌:用于签名处理,下文会介绍相关流程。
- EncodingAESKey:将用作消息体加解密密钥。
- 消息加解密方式:
- 明文模式:不使用消息加解密,明文发送,安全系数较低,不建议使用。
- 兼容模式:明文、密文共存,不建议使用。
- 安全模式:使用消息加解密,纯密文,安全系数高,强烈推荐使用。
- 数据格式:消息体的格式,可选 XML 或 JSON。
# 1.2 发起验证
点击「提交」后,微信服务器会对开发者服务器发起验证,请在提交前按以下方式开发:
微信服务器将发送 GET 请求到填写的服务器地址 URL 上,GET 请求携带参数如下表所示:
| 参数 | 描述 |
|---|---|
| signature | 签名 |
| timestamp | 时间戳 |
| nonce | 随机数 |
| echostr | 随机字符串 |
其中,signature 签名的生成方式是:
- 将 Token、timestamp、nonce 三个参数进行字典序排序。
- 将三个参数字符串拼接成一个字符串进行 sha1 计算签名,即可获得 signature。
开发者需要校验 signature 是否正确,以判断请求是否来自微信服务器,验签通过后,请原样返回 echostr 字符串。
举例:假设填写的 URL = "https://www.qq.com/revice",Token = "AAAAA"。
- 推送的 URL 链接:https://www.qq.com/revice?signature=f464b24fc39322e44b38aa78f5edd27bd1441696&echostr=4375120948345356249×tamp=1714036504&nonce=1514711492
- 将 token、timestamp、nonce 三个参数进行字典序排序,排序后结果为:["1514711492","1714036504","AAAAA"]。
- 将三个参数字符串拼接成一个字符串:"15147114921714036504AAAAA"
- 进行 sha1 计算签名:f464b24fc39322e44b38aa78f5edd27bd1441696
- 与 URL 链接中的 signature 参数进行对比,相等说明请求来自微信服务器,合法。
- 构造回包返回微信,回包消息体内容为 URL 链接中的 echostr 参数 4375120948345356249。
为了便于开发者调试,我们提供了 URL 验证工具 供开发者使用。
开发者需填写 AccessToken、URL 地址、Token,点击「检查参数并发起验证」后,调试工具会发送 GET 请求到 URL 所指的服务器,并返回相关调试信息。
# 2、接收消息推送
当特定消息或事件触发时,微信服务器会将消息(或事件)的数据包以 POST 请求发送到开发者配置的 URL,下面以 debug_demo 事件为例,详细介绍整个过程:
# 2.1 消息解密方式为明文模式
- 假设 URL 配置为 https://www.qq.com/revice,数据格式为 JSON,Token = "AAAAA"。
- 推送的 URL 链接:https://www.qq.com/recive?signature=899cf89e464efb63f54ddac96b0a0a235f53aa78×tamp=1714037059&nonce=486452656
- 推送的包体:
{
"ToUserName": "gh_97417a04a28d",
"FromUserName": "o9AgO5Kd5ggOC-bXrbNODIiE3bGY",
"CreateTime": 1714037059,
"MsgType": "event",
"Event": "debug_demo",
"debug_str": "hello world"
}
- 校验 signature 签名是否正确,以判断请求是否来自微信服务器。
- 将 token、timestamp(URL 参数中的)、nonce(URL 参数中的)三个参数进行字典序排序,排序后结果为:["1714037059","486452656","AAAAA"]
- 将三个参数字符串拼接成一个字符串:"1714037059486452656AAAAA"
- 进行 sha1 计算签名:899cf89e464efb63f54ddac96b0a0a235f53aa78
- 与 URL 链接中的 signature 参数进行对比,相等说明请求来自微信服务器,合法。
- 回包给微信,具体回包内容取决于特定接口文档要求,如无特定要求,回复空串或者 success 即可。
# 2.2 消息解密方式为安全模式
- 假设 URL 配置为 https://www.qq.com/revice,数据格式为 JSON,Token = "AAAAA",EncodingAESKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",网站应用 Appid = "wxba5fad812f8e6fb9"。
- 推送的 URL 链接:https://www.qq.com/recive?signature=6c5c811b55cc85e0e1b54100749188c20beb3f5d×tamp=1714112445&nonce=415670741&openid=o9AgO5Kd5ggOC-bXrbNODIiE3bGY&encrypt_type=aes&msg_signature=046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
- 推送的包体:
{
"ToUserName": "gh_97417a04a28d",
"Encrypt": "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04="
}
校验 msg_signature 签名是否正确,以判断请求是否来自微信服务器。注意:不要使用 signature 验证!
- 将 token、timestamp(URL 参数中的)、nonce(URL 参数中的)、Encrypt(包体内的字段)四个参数进行字典序排序,排序后结果为: ["+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04=", "1714112445", "415670741", "AAAAA"]。
- 将四个参数字符串拼接成一个字符串,然后进行 sha1 计算签名:046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
- 与 URL 参数中的 msg_signature 参数进行对比,相等说明请求来自微信服务器,合法。
解密消息体 "Encrypt" 密文。
- AESKey = Base64_Decode(EncodingAESKey + "="),EncodingAESKey 尾部填充一个字符的 "=",用 Base64_Decode 生成 32 个字节的 AESKey;
- 将 Encrypt 密文进行 Base64 解码,得到 TmpMsg;
- 将 TmpMsg 使用 AESKey 进行 AES 解密,得到 FullStr。AES 采用 CBC 模式,秘钥长度为 32 个字节(256 位),数据采用 PKCS#7 填充。微信团队提供了多种语言的示例代码(包括 PHP、Java、C++、Python、C#),请开发者尽量使用示例代码,仔细阅读技术文档、示例代码及其注释后,再进行编码调试。示例下载
- FullStr = random(16B) + msg_len(4B) + msg + appid,其中:
- random(16B) 为 16 字节的随机字符串;
- msg_len 为 msg 长度,占 4 个字节(网络字节序);
- msg 为解密后的明文;
- appid 为网站应用 Appid,开发者需验证此 Appid 是否与自身网站应用相符。
回包给微信服务器,假设回包包体的明文内容为 "{"demo_resp":"good luck"}",下面介绍如何对回包进行加密:
回包格式如下,具体取决于你配置的数据格式(JSON 或 XML),其中:
- Encrypt:加密后的内容;
- MsgSignature:签名,微信服务器会验证签名;
- TimeStamp:时间戳;
- Nonce:随机数
{ "Encrypt": "${msg_encrypt}$", "MsgSignature": "${msg_signature}$", "TimeStamp": ${timestamp}$, "Nonce": ${nonce}$ }<xml> <Encrypt><![CDATA[${msg_encrypt}$]]></Encrypt> <MsgSignature><![CDATA[${msg_signature}$]]></MsgSignature> <TimeStamp>${timestamp}$</TimeStamp> <Nonce><![CDATA[${nonce}$]]></Nonce> </xml>Encrypt 的生成方法:
- AESKey = Base64_Decode(EncodingAESKey + "=");
- 构造 FullStr = random(16B) + msg_len(4B) + msg + appid;
- 将 FullStr 用 AESKey 进行 AES 加密得到 TmpMsg(AES 采用 CBC 模式,PKCS#7 填充);
- 对 TmpMsg 进行 Base64 编码,得到 Encrypt。
TimeStamp 由开发者生成,使用当前时间戳即可。
Nonce 回填 URL 参数中的 nonce 参数即可。
MsgSignature 的生成方法:将 token、TimeStamp、Nonce、Encrypt 四个参数进行字典序排序后拼接,再进行 sha1 计算签名。
最终回包示例:
{
"Encrypt": "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ==",
"MsgSignature": "1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1",
"TimeStamp": 1713424427,
"Nonce": "415670741"
}
为了便于开发者调试,我们提供了相关的调试工具(请求构造、调试工具)供开发者使用。
- 「请求构造」允许开发者填写相关参数后,生成 debug_demo 事件发包或回包的相关调试信息,供开发者使用。
- 「调试工具」允许开发者填写 AccessToken、Body 后,微信服务器会拉取你在网站应用后台配置的消息推送配置,实际推送一条 debug_demo 事件供开发者调试。