# 消息推送

微信云托管支持接收微信消息推送，走内网链路，无需加解密和签名。

当微信云托管消息推送开启时，消息不会推送到开发者服务器上，而是会推送到开发者指定的云托管服务中。

## 配置方式

前往[微信云托管控制台-设置-全局设置-消息推送](https://cloud.weixin.qq.com/cloudrun/settings/other)中配置

![配置消息](https://res8.wxqcloud.qq.com.cn/wxdoc/df964378-d311-4850-9696-cc5d1fbd504f.png)

配置时需要的信息解释如下：

- 环境 ID：选择微信云托管的哪个环境接收消息推送
- 服务名称：选择接收消息推送的服务，只需配置 1 个服务即可接收所有类型消息；
- path：服务下哪个接口接收即写该接口在服务内的路径即可，比如根路径填写 `/`

## 资源复用配置

如果当前环境有配置资源复用给其他小程序/公众号，则配置窗口会变成如下：

![配置消息](https://res8.wxqcloud.qq.com.cn/wxdoc/c66f6244-e35e-47cc-a54f-f0916b2c8f79.png)

你可以选择其他已复用的小程序/公众号，配置推送路径。

需要注意的是：配置确认的扫码，需要是**目标「小程序/公众号」的管理员**，而不是环境的管理员或者环境所属的账号管理员。

## 配置解绑

当想要取消消息推送时，直接在控制台列表选择操作解绑。

如果你的公众号/小程序，之前配置过服务器路径接收消息，配置消息推送后，将会覆盖服务器路径。

但解绑后，原有的服务器路径不会生效，需要先在[开发者后台](https://mp.weixin.qq.com)停用，再启用，就可以恢复正常了。

## 配置测试

配置消息推送时，微信后台会向配置的服务发起一个检测请求。

当配置格式为 JSON 时，请求体为：

```json
{ 
  "action": "CheckContainerPath"
}
```

当配置格式为 XML 时，请求体为：

```xml
<xml>
  <action>CheckContainerPath</action>
</xml>
```

开发者回复 success 或回复空即可完成测试。

**需要注意，路径返回的 `Status` 需要为 200，如果是非 200 将会导致路径配置检查失败**

## 确认消息来源

若云托管未开启公网访问，则可以信任所有消息推送。

若云托管开启了公网访问，需要验证消息推送的请求头，带 **x-wx-source** 的请求才是微信侧发起的推送。

消息推送如果是 JSON 形式，则收到的信息格式如下：

``` json
{
  "ToUserName": "gh_919b00572d95", // 小程序/公众号的原始ID，资源复用配置多个时可以区别消息是给谁的
  "FromUserName": "oVneZ57wJnV-ObtCiGv26PRrOz2g", // 该小程序/公众号的用户身份openid
  "CreateTime": 1651049934, // 消息时间
  "MsgType": "text", // 消息类型
  "Content": "回复文本", // 消息内容
  "MsgId": 23637352235060880 // 唯一消息ID，可能发送多个重复消息，需要注意用此ID去重
}
```

## 消息回复

消息推送有两种，被动回复和主动回复。

### 1. 被动回复

原理可以参考[此文档](/doc/service/guide/product/message/Receiving_standard_messages.md)，发送被动响应消息其实并不是一种接口，而是对微信服务器发过来消息的一次回复。

**需要注意，被动回复只支持公众号，小程序需要使用主动回复。公众号具体的回复格式可参考[开发指引](/miniprogram/dev/wxcloudservice/wxcloudrun/src/development/weixin/callback)。**

### 2. 主动回复

小程序，以及公众号无法即时回复场景，可以使用 API 异步发送来完成，这也是微信团队推荐的做法。

比如接收到了「小程序/公众号」的客服消息，可以在请求体中得到发送者 openid，unionid，以及发送的内容。

接下来就可以通过开放接口服务方式，[发送客服消息](/miniprogram/dev/server/API/kf-mgnt/kf-message/api_sendcustommessage.md)来完成回复操作。

详细的主动回复例子请参考[开发指引](/miniprogram/dev/wxcloudservice/wxcloudrun/src/development/weixin/callback)

代码如下：

``` js
const request = require('request')
return new Promise((resolve, reject) => {
  request({
    method: 'POST',
    url: 'http://api.weixin.qq.com/cgi-bin/message/custom/send',
    // 资源复用情况下，参数from_appid应写明发起方appid
    // url: 'http://api.weixin.qq.com/cgi-bin/message/custom/send?from_appid=wxxxxx'
    body: JSON.stringify({
      touser: "OPENID", // 一般是消息推送body的FromUserName值，为用户的openid
      msgtype: "text",
      text: {
        content: "Hello World"
      }
    })
  },function (error, response) {
    console.log('接口返回内容', response.body)
    resolve(JSON.parse(response.body))
  })
})
```

在使用前请开启「开放接口服务」，并配置 `cgi-bin/message/custom/send` 到云调用白名单接口，具体参考[文档](open)

## 代码示例

以下演示使用 `node.js` 来构建接收消息的服务，共三个文件。详细的包含回复的代码示例可以参考[开发指引](/miniprogram/dev/wxcloudservice/wxcloudrun/src/development/weixin/callback)

`index.js` 文件

```js
const express = require('express')

const app = express()

app.use(express.json())

app.post('/', async (req, res) => {
  console.log('消息推送', req.body)
  res.send('success') // 不进行任何回复，直接返回success，告知微信服务器已经正常收到。
});

app.listen(80, function(){
  console.log('服务启动成功！')
})
```

`Dockerfile` 文件

``` dockerfile
FROM node:12-slim

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . ./

CMD [ "node", "index.js"]
```

`package.json` 文件

```json
{
  "name": "cloudbase-push",
  "version": "1.0.0",
  "description": "call push server",
  "main": "index.js",
  "scripts": {},
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.4"
  }
}
```

将 3 个文件组成文件夹，版本创建上传，端口填写 `80`，创建版本成功后，部署发布。

在消息推送配置填写对应的服务，路径填写 `/`

填写后在[控制台-日志](https://cloud.weixin.qq.com/cloudrun/containerlog)中可以看到如下

![](https://res8.wxqcloud.qq.com.cn/wxdoc/aa91b669-e3fe-4085-b184-ff4071a47bb2.png)
