# 消息推送开发手册

消息推送是开放平台推出的一种主动推送服务，基于该推送服务，开发者及时获取开放平台相关信息，无需调用 API。

总数据链路如图所示：

![](https://res.wx.qq.com/op_res/CyXI7cGX7jxeP-vdY2Hkm9s2cMZlsxeY23fkgw44pPOtTwMbZQq-iM-3Lv4054rfJtUFVOwyac0E9I3vFclKqw)

## 1、消息推送服务器配置

消息推送服务于小程序、公众号、小游戏、视频号小店、第三方平台，这里介绍在网站应用的配置。

### 1.1 填写相关信息

登录 [OPEN 平台](https://open.weixin.qq.com/)，在「管理中心」-「网站应用」-「消息推送」中，需填写以下信息：

1. URL 服务器地址：开发者用来接收微信消息和事件的接口 URL，必须以 http:// 或 https:// 开头，分别支持 80 端口和 443 端口。
2. Token 令牌：用于签名处理，下文会介绍相关流程。
3. EncodingAESKey：将用作消息体加解密密钥。
4. 消息加解密方式：
   - 明文模式：不使用消息加解密，明文发送，安全系数较低，不建议使用。
   - 兼容模式：明文、密文共存，不建议使用。
   - 安全模式：使用消息加解密，纯密文，安全系数高，强烈推荐使用。
5. 数据格式：消息体的格式，可选 XML 或 JSON。

![](https://res.wx.qq.com/op_res/bxYIwsDtqGavFRXcLZGIpHI8pNeDcp9YZsXiTc_3_gJqPgV1E4PBTq_u_DJH8a88NDuQDpytYvq6bPltDaheOg)

### 1.2 发起验证

点击「提交」后，微信服务器会对开发者服务器发起验证，请在提交前按以下方式开发：

微信服务器将发送 GET 请求到填写的服务器地址 URL 上，GET 请求携带参数如下表所示：

| 参数 | 描述 |
| :--- | :--- |
| signature | 签名 |
| timestamp | 时间戳 |
| nonce | 随机数 |
| echostr | 随机字符串 |

其中，signature 签名的生成方式是：

1. 将 Token、timestamp、nonce 三个参数进行字典序排序。
2. 将三个参数字符串拼接成一个字符串进行 sha1 计算签名，即可获得 signature。

开发者需要校验 signature 是否正确，以判断请求是否来自微信服务器，验签通过后，请原样返回 echostr 字符串。

举例：假设填写的 URL = "https://www.qq.com/revice"，Token = "AAAAA"。

1. 推送的 URL 链接：https://www.qq.com/revice?signature=f464b24fc39322e44b38aa78f5edd27bd1441696&echostr=4375120948345356249&timestamp=1714036504&nonce=1514711492
2. 将 token、timestamp、nonce 三个参数进行字典序排序，排序后结果为：["1514711492","1714036504","AAAAA"]。
3. 将三个参数字符串拼接成一个字符串："15147114921714036504AAAAA"
4. 进行 sha1 计算签名：f464b24fc39322e44b38aa78f5edd27bd1441696
5. 与 URL 链接中的 signature 参数进行对比，相等说明请求来自微信服务器，合法。
6. 构造回包返回微信，回包消息体内容为 URL 链接中的 echostr 参数 4375120948345356249。

为了便于开发者调试，我们提供了 [URL 验证工具](https://developers.weixin.qq.com/apiExplorer?type=messagePush) 供开发者使用。

![](https://res.wx.qq.com/op_res/CyXI7cGX7jxeP-vdY2Hkm9kdbt1XFpcK-5W3xMW-rUdMFepPUAjXfDxv7v-V28ytPPMMydovWViBMEO4PKXFug)

开发者需填写 [AccessToken](/miniprogram/dev/server/API/mp-access-token/api_getaccesstoken.md)、URL 地址、Token，点击「检查参数并发起验证」后，调试工具会发送 GET 请求到 URL 所指的服务器，并返回相关调试信息。

## 2、接收消息推送

当特定消息或事件触发时，微信服务器会将消息（或事件）的数据包以 POST 请求发送到开发者配置的 URL，下面以 debug_demo 事件为例，详细介绍整个过程：

### 2.1 消息解密方式为明文模式

1. 假设 URL 配置为 https://www.qq.com/revice，数据格式为 JSON，Token = "AAAAA"。
2. 推送的 URL 链接：https://www.qq.com/recive?signature=899cf89e464efb63f54ddac96b0a0a235f53aa78&timestamp=1714037059&nonce=486452656
3. 推送的包体：

```json
{
    "ToUserName": "gh_97417a04a28d",
    "FromUserName": "o9AgO5Kd5ggOC-bXrbNODIiE3bGY",
    "CreateTime": 1714037059,
    "MsgType": "event",
    "Event": "debug_demo",
    "debug_str": "hello world"
}
```

4. 校验 signature 签名是否正确，以判断请求是否来自微信服务器。
    1. 将 token、timestamp（URL 参数中的）、nonce（URL 参数中的）三个参数进行字典序排序，排序后结果为：["1714037059","486452656","AAAAA"]
    2. 将三个参数字符串拼接成一个字符串："1714037059486452656AAAAA"
    3. 进行 sha1 计算签名：899cf89e464efb63f54ddac96b0a0a235f53aa78
    4. 与 URL 链接中的 signature 参数进行对比，相等说明请求来自微信服务器，合法。
5. 回包给微信，具体回包内容取决于特定接口文档要求，如无特定要求，回复空串或者 success 即可。

### 2.2 消息解密方式为安全模式

1. 假设 URL 配置为 https://www.qq.com/revice，数据格式为 JSON，Token = "AAAAA"，EncodingAESKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"，网站应用 Appid = "wxba5fad812f8e6fb9"。
2. 推送的 URL 链接：https://www.qq.com/recive?signature=6c5c811b55cc85e0e1b54100749188c20beb3f5d&timestamp=1714112445&nonce=415670741&openid=o9AgO5Kd5ggOC-bXrbNODIiE3bGY&encrypt_type=aes&msg_signature=046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
3. 推送的包体：

```json
{
    "ToUserName": "gh_97417a04a28d",
    "Encrypt": "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04="
}
```

4. 校验 msg_signature 签名是否正确，以判断请求是否来自微信服务器。注意：不要使用 signature 验证！
    - 将 token、timestamp（URL 参数中的）、nonce（URL 参数中的）、Encrypt（包体内的字段）四个参数进行字典序排序，排序后结果为：
    ["+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04=",
    "1714112445",
    "415670741",
    "AAAAA"]。
    - 将四个参数字符串拼接成一个字符串，然后进行 sha1 计算签名：046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
    - 与 URL 参数中的 msg_signature 参数进行对比，相等说明请求来自微信服务器，合法。

5. 解密消息体 "Encrypt" 密文。
    1. AESKey = Base64_Decode(EncodingAESKey + "=")，EncodingAESKey 尾部填充一个字符的 "="，用 Base64_Decode 生成 32 个字节的 AESKey；
    2. 将 Encrypt 密文进行 Base64 解码，得到 TmpMsg；
    3. 将 TmpMsg 使用 AESKey 进行 AES 解密，得到 FullStr。AES 采用 CBC 模式，秘钥长度为 32 个字节（256 位），数据采用 PKCS#7 填充。微信团队提供了多种语言的示例代码（包括 PHP、Java、C++、Python、C#），请开发者尽量使用示例代码，仔细阅读技术文档、示例代码及其注释后，再进行编码调试。[示例下载](https://wximg.gtimg.com/shake_tv/mpwiki/cryptoDemo.zip)
    4. FullStr = random(16B) + msg_len(4B) + msg + appid，其中：
        - random(16B) 为 16 字节的随机字符串；
        - msg_len 为 msg 长度，占 4 个字节（网络字节序）；
        - msg 为解密后的明文；
        - appid 为网站应用 Appid，开发者需验证此 Appid 是否与自身网站应用相符。

6. 回包给微信服务器，假设回包包体的明文内容为 "{\"demo_resp\":\"good luck\"}"，下面介绍如何对回包进行加密：

7. 回包格式如下，具体取决于你配置的数据格式（JSON 或 XML），其中：
    - Encrypt：加密后的内容；
    - MsgSignature：签名，微信服务器会验证签名；
    - TimeStamp：时间戳；
    - Nonce：随机数

    ```json
    {
        "Encrypt": "${msg_encrypt}$",
        "MsgSignature": "${msg_signature}$",
        "TimeStamp": ${timestamp}$,
        "Nonce": ${nonce}$
    }
    ```

    ```xml



        ${timestamp}$


    ```

8. Encrypt 的生成方法：
    1. AESKey = Base64_Decode(EncodingAESKey + "=")；
    2. 构造 FullStr = random(16B) + msg_len(4B) + msg + appid；
    3. 将 FullStr 用 AESKey 进行 AES 加密得到 TmpMsg（AES 采用 CBC 模式，PKCS#7 填充）；
    4. 对 TmpMsg 进行 Base64 编码，得到 Encrypt。

9. TimeStamp 由开发者生成，使用当前时间戳即可。
10. Nonce 回填 URL 参数中的 nonce 参数即可。
11. MsgSignature 的生成方法：将 token、TimeStamp、Nonce、Encrypt 四个参数进行字典序排序后拼接，再进行 sha1 计算签名。

12. 最终回包示例：

```json
{
    "Encrypt": "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ==",
    "MsgSignature": "1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1",
    "TimeStamp": 1713424427,
    "Nonce": "415670741"
}
```

为了便于开发者调试，我们提供了相关的调试工具（[请求构造](https://developers.weixin.qq.com/apiExplorer?type=messagePush)、[调试工具](https://developers.weixin.qq.com/apiExplorer?type=messagePush)）供开发者使用。

- 「请求构造」允许开发者填写相关参数后，生成 debug_demo 事件发包或回包的相关调试信息，供开发者使用。

![](https://res.wx.qq.com/op_res/CyXI7cGX7jxeP-vdY2HkmzPAxYtOmSK_jSvQsQKLjBlK9LTCJjQY14AmHwQmPIcyQWFYPWpn8lqzVjfQKB9y1w)

- 「调试工具」允许开发者填写 [AccessToken](/miniprogram/dev/server/API/mp-access-token/api_getaccesstoken.md)、Body 后，微信服务器会拉取你在网站应用后台配置的消息推送配置，实际推送一条 debug_demo 事件供开发者调试。

![](https://res.wx.qq.com/op_res/CyXI7cGX7jxeP-vdY2Hkm-hEi9O6s8jFZI7ewGAoi8bUp6X86EpNxCM2wn_rnHrhQ7ByOfhYVmrN-TLJVR69HQ)
