# Messaging

Message push is an active push service launched by the open platform. Based on the push service, developers can get the relevant information of the open platform in time without calling API. There are currently three ways to access:

# The developer server receives message pushes

Total data link as shown in Figure:

# Messaging server configuration

Messaging is served by [[ Weixin Mini Program 、 Official Account 、 MiniGame 、WeChat Channels Shop, Third Party Platform, here the Mini Program platform configuration.

# Fill in relevant information

To log in Weixin Mini Program To manage the backEND , in Development - Development Management - Messaging Configuration, fill in the following information:

  1. URL server address: The interface URL used by developers to receive WeChat messages and events must begin with http:// or https:// and support ports 80 and 443 respectively.
  2. Token: Used for signature processing, which is described below.
  3. EncodingAESKey: Will be used as the message body encryption and decryption key.
  4. How to decrypt a message:
    • Text mode: No message decryption is used, text is sent, the security is low, and it is not recommended.
    • Compatibility mode: plain text, cipher text coexist, not recommended.
    • Security Mode: Use message decryption, plain ciphertext, high security coefficient, highly recommended.
  5. Data format: The format of the message body, either XML or JSON.

# Initiate validation

After clicking "Submit," the WeChat server will validate the developer server. Please develop as follows before submitting: WeChat The server will send a GET request to the server address URL filled in. The GET request carries parameters as shown in the table below:

parameter describe
signature autograph
timestamp timestamp
nonce random number
echostr Random character string

Where the signature is generated by:

  1. The three parameters of Token, timestamp and nonce are lexicographically sorted.
  2. A signature is obtained by concatenating three argument character strings into one string and signing it with sha1 computations. Developers need to verify the signature is correct, to determine whether the request from the WeChat server, check through, please return the echo str character string.

Example: Suppose fill in URL = "https://www.qq.com/revice," Token = "AAAAA."

  1. Push URL link: https://www.qq.com/revice?signature=f464b24fc39322e44b38aa78f5edd27bd1441696&echostr=4375120948345356249×tamp=1714036504&nonce=1514711492
  2. The token, timestamp, nonce three parameters are lexicographic sort, sort the result is: ["1514711492," "1714036504," "AAAAA"].
  3. Concatenate the three argument strings into one character string: "15147114921714036504AAA"
  4. Perform sha1 calculation Signature: f464b24fc39322e44b38aa78f5edd27bd1441696
  5. In contrast to the signature parameter in the URL link, equality indicates that the request is valid from the WeChat server.
  6. The constructed back package returns WeChat with the echostr parameter 4375120948345356249 in the URL link.

To facilitate debugging by developers, we provide URL validation tool for developers to use. Developers need to fill in AccessToken , URLAddress, Token, and click "Check parameters and initiate validation," the debugging tool will send a GET request to the server referred to by the URL and return relevant debugging information.

# Receive a message push

When a specific message or event is triggered, the WeChat server sends the packet of the message (or event) as a POST request to the developer-configured URL. Take the example of the "debug_demo" event to detail the process:

# Message decryption is in plain text mode

  1. Assume that URL is configured as https://www.qq.com/revice and the data format is JSON, Token = "AAAAA."
  2. Push URL link: https://www.qq.com/recive?signature=899cf89e464efb63f54ddac96b0a0a235f53aa78×tamp=1714037059&nonce=486452656
  3. The pushed wrap:
{
    "ToUserName": "gh_97417a04a28d",
    "FromUserName": "o9AgO5Kd5ggOC-bXrbNODIiE3bGY",
    "CreateTime": 1714037059,
    "MsgType": "event",
    "Event": "debug_demo",
    "debug_str": "hello world"
}
  1. Verifies that the signature is correct to determine if the request is from the WeChat server.
    1. Lexicographic sorting of token, timestamp (in URL parameter), nonce (in the URL parameter), and the result is: ["1714037059," "486452656," "AAAAA"]
    2. Concatenate the three argument character strings into one string: "1714037059486452656AAA"
    3. Perform sha1 calculationSigned: 899cf89e464efb63f54ddac96b0a0a235f53aa78
    4. In contrast to the signature parameter in the URL link, equality indicates that the request is valid from the WeChat server.
  2. Back to WeChat, the specific back to the content of the package depends on the specific interface document requirements, such as no specific requirements, the return of the empty string or success can be.

# The message is decrypted in secure mode

  1. Assume that URL is configured with https://www.qq.com/revice and the data format isJSON,Token="AAAAA",EncodingAESKey="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",Weixin Mini Program Appid="wxba5fad812f8e6fb9"。
  2. Push URL link:: https://www.qq.com/recive?signature=6c5c811b55cc85e0e1b54100749188c20beb3f5d×tamp=1714112445&nonce=415670741&openid=o9AgO5Kd5ggOC-bXrbNODIiE3bGY&encrypt_type=aes&msg_signature=046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
  3. The pushed wrap:
{
    "ToUserName": "gh_97417a04a28d",
    "Encrypt": "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04="
}
  1. Verify that the msg_signature signature is correct to determine if the request is from the WeChat server.Note: Do not use signature validation!
    • Lexicographically sort token, timestamp (in the URL parameter), nonce (in the URL parameter), and Encrypt (in the field inside the package). The result is: ["+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04=", "1714112445", "415670741", "AAAAA"]。
    • The four parameter string stitching into a character string, and then calculate the signature sha1: 046e02f8204d34f8ba5fa3b1db9908f2e9b3
    • In contrast to the msg_signature parameter in the URL parameter, equality indicates that the request is valid from the WeChat server.
  2. Decrypts the message body "Encrypt" ciphertext.
    1. AESKey = Base64_Decode (EncodingAESKey + "="), EncodingAESKey ends with a character "=," using Base64_Decode to generate a 32-byte AESKey;
    2. Base64 decodes the Encrypt ciphertext to get TmpMsg with a byte length of 224
    3. The TmpMsg is AES decrypted using AESKey to get a FullStr with a byte length of 205. AES uses CBC mode, the key length is 32 bytes (256 bits), and the data is filled with PKCS # 7; PKCS # 7: K is the number of bytes of the key (32), Buf is the content to be encrypted, and N is the number of bytes. Buf needs to be filled in as an integer multiple of K. Fill the tail of the Buf with (K-N% K) bytes, each containing (K-N% K).WeChat The team provides sample code in a variety of languages (including PHP, Java, C + +, Python, C #) and asks developers to use sample code whenever possible, and to carefully read the technical documentation, sample code, and annotations before coding debugging. Sample Download
    4. FullStr = random(16B) + msg_len(4B) + msG + AppID where:
      • Random (16B) is a 16-byte random character string;
      • Msg_len is the length of msg, accounting for 4 bytes (network byte order);
      • MSG is the decrypted plaintext;
      • AppID is a Weixin Mini Program Appid, and developers need to verify that this Appid matches their Mini Program.
    5. In this example:
      • random(16B)="a8eedb185eb2fecf"
      • Msg_len = 167 (note: 4 bytes in network byte order)
      • msg="{"ToUserName":"gh_97417a04a28d","FromUserName":"o9AgO5Kd5ggOC-bXrbNODIiE3bGY","CreateTime":1714112445,"MsgType":"event","Event":"debug_demo","debug_str":"hello world"}"
      • appid="wxba5fad812f8e6fb9"
  3. To reply back to the WeChat server, you first need to determine the plaintext content of the reply packet, depending on the specific interface document requirements. If there is no specific requirement, reply a string or success (no encryption required), and other reply content needs to be encrypted.Assuming that the plain text in the body of the envelope is "{" demo_resp ":" goodluck "}" and the data format is JSON, here's how to encrypt the envelope:
  4. Depending on the data format you configure (JSON or XML), where:
    • Encrypt: the encrypted content;
    • MsgSignature: Signature, WeChat The server verifies the signature;
    • TimeStamp: Time stamp;
    • Nonce: Take the chance
    {
        "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>
    
  5. Encrypt的生成方法:
    1. AESKey = Base64_Decode( EncodingAESKey + "=" ),EncodingAESKey 尾部填充一个字符的 "=", 用 Base64_Decode 生成 32 个字节的 AESKey;
    2. 构造FullStr=random(16B) + msg_len(4B) + msg + appid,其中
      • random(16B)为 16 字节的随机字符串;
      • msg_len 为 msg 长度,占 4 个字节(网络字节序);
      • msg为明文;
      • appid为小程序Appid。
    3. 在此示例中:
      • random(16B)="707722b803182950"
      • msg_len=25(注意:需按网络字节序,占4个字节)
      • msg="{"demo_resp":"good luck"}"
      • appid="wxba5fad812f8e6fb9"
      • FullStr的字节大小为63
    4. 将FullStr用AESKey进行加密,得到TmpMsg,字节大小为64。AES 采用 CBC 模式,秘钥长度为 32 个字节(256 位),数据采用 PKCS#7 填充; PKCS#7:K 为秘钥字节数(采用 32),Buf 为待加密的内容,N 为其字节数。Buf 需要被填充为 K 的整数倍。在 Buf 的尾部填充(K - N%K)个字节,每个字节的内容 是(K - N%K)。微信团队提供了多种语言的示例代码(包括 PHP、Java、C++、Python、C#),请开发者尽量使用示例代码,仔细阅读技术文档、示例代码及其注释后,再进行编码调试。示例下载
    5. 对TmpMsg进行Base64编码,得到Encrypt="ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ=="。
  6. TimeStamp由开发者生成,使用当前时间戳即可,示例使用1713424427。
  7. Nonce回填URL参数中的nonce参数即可,示例使用415670741。
  8. MsgSignature的生成方法:
    1. 将token、TimeStamp(回包中的)、Nonce(回包中的)、Encrypt(回包中的)四个参数进行字典序排序,排序后结果为: ["1713424427", "415670741", "AAAAA", "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ=="]
    2. 将四个参数字符串拼接成一个字符串,并进行sha1计算签名:1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1
  9. 最终回包为:
{
    "Encrypt": "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ==",
    "MsgSignature": "1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1",
    "TimeStamp": 1713424427,
    "Nonce": "415670741"
}

为了便于开发者调试,我们提供了相关的调试工具(请求构造调试工具)供开发者使用。

  • “请求构造”允许开发者填写相关参数后,生成debug_demo事件发包或回包的相关调试信息,供开发者使用。
  • “调试工具”允许开发者填写AccessToken、Body后,微信服务器会拉取你在小程序后台配置的消息推送配置,实际推送一条debug_demo事件供开发者调试。

# 云函数接收消息推送

需开发者工具版本至少 1.02.1906252

开通了云开发的小程序可以使用云函数接收消息推送,目前仅支持客服消息推送。

接入步骤如下:

  1. 云开发控制台中填写配置并上传
  2. 云函数中处理消息

# 第一步:开发者工具云开发控制台中增加配置

前往路径“「云开发」-「设置」-「其他设置」-「消息推送」”,选择推送模式为云函数; 添加消息推送配置。消息类型对应收包的 MsgType,事件类型对应收包的 Event,同一个 <消息类型, 事件类型> 二元组只能推到一个环境的一个云函数。例如客服消息文本消息对应的就是消息类型为 text,事件类型为空。具体值请查看各个消息的消息格式。 多个消息类型、事件类型多次添加消息推送配置即可。

注意:如在云函数中配置了某个类型的消息,该类型消息将不再推送至“微信公众平台-开发设置-消息推送”中配置的域名中。

# 第二步:云函数中处理消息

云函数被触发时,其 event 参数即是接口所定义的 JSON 结构的对象(统一 JSON 格式,不支持 XML 格式)。

以客服消息为例,接收到客服消息推送时,event 结构如下:

{
  "FromUserName": "ohl4L0Rnhq7vmmbT_DaNQa4ePaz0",
  "ToUserName": "wx3d289323f5900f8e",
  "Content": "Testing,"
  "CreateTime": 1555684067,
  "MsgId": "49d72d67b16d115e7935ac386f2f0fa41535298877_1555684067",
  "MsgType": "text"
}

此时可调用客服消息发送接口回复消息,一个简单的接收到消息后统一回复 “收到” 的示例如下:

/ / Cloud function entry file
const cloud = require('wx-server-sdk')

cloud.init()

/ / Cloud Function Entry Function
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  
  await cloud.openapi.customerServiceMessage.send({
    touser: wxContext.OPENID,
    msgtype: 'text',
    text: {
      Content: 'Received',
    },
  })

  return 'success'
}

# 微信云托管接收消息推送

使用微信云托管的小程序/公众号可以使用云托管服务接收消息推送,只需配置一个云托管服务即可支持所有类型的消息推送。

接入步骤如下:

  1. 微信云托管控制台中填写配置
  2. 云托管服务中处理消息

# 第一步 云托管控制台填写配置

前往路径“「微信云托管」-「设置」-「其他设置」-「消息推送」”中配置;

点击配置,选择目标云开发环境、填写对应的云托管服务路径(路径可前往“云托管”-“服务列表”-“路径字段”中复制)、选择推送类型;

  • 环境ID:选择接收消息推送
  • 服务名称:接收消息推送的服务,只需配置1个服务即可接收所有类型消息;
  • path:服务下哪个接口接收即写该接口在服务内的路径即可;
  • 推送模式:支持JSON、XML两种模式;

配置完成后,该云托管服务即可接收当前小程序/公众号下所有类型消息推送。

# 配置测试

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

当配置格式为 JSON 时,请求体为:

{ "action": "CheckContainerPath"}

当配置格式为 XML 时,请求体为:

CheckContainerPath

开发者回复 success 或回复空即可。

# 确认消息来源

若云托管未开启公网访问,则可以信任所有消息推送。若云托管开启了公网访问,需要验证消息推送的请求头,带 x-wx-sources 的请求才是微信侧发起的推送。

# 第二步 云托管服务中处理消息

下面的例子展示如何使用云托管结合消息推送,实现客服消息回复。 注意:需要先部署好以下的镜像,再在设置-其他设置-消息推送中,填入对应服务的路径和环境 ID。

const express = require('express')
const bodyParser = require('body-parser')
const axios = require('axios')

const PORT = process.env.PORT || 80
const HOST = '0.0.0.0'

// App
const app = express()

app.use(bodyParser.raw())
app.use(bodyParser.json({}))
app.use(bodyParser.urlencoded({ extended: true }))

const client = axios.default

app.all('/', async (req, res) => {
    const headers = req.headers
    const weixinAPI =`http://api.weixin.qq.com/cgi-bin/message/custom/send`
    const payload = {
        touser: headers['x-wx-openid'],
        msgtype: 'text',
        text: {
            Content:`Cloud hosting successfully received the message push, as follows:\n${JSON.stringify(req.body, null, 2)}`
        }
    }
    // dispatch to wx server
    const result = await client.post(weixinAPI, payload)
    console.log('received request', req.body, result.data)
    res.send('success')
});

app.listen(PORT, HOST)
console.log(`Running on http://${HOST}:${PORT}`)

配置成功后,使用 <button open-type="contact"> 类型的按钮唤起客服会话,发送任意消息即可看到云托管处理的回复。