跳转至

消息推送接口说明

1. 请求方式

  • 协议:HTTP
  • 方法:POST
  • Content-Type:application/json

2. 请求参数

服务端会接收到如下格式的 JSON:

{
  "data": {
    "id": "消息ID",
    "chat_id": "对话ID",
    "chat_title": "对话名称",
    "content": "消息内容",
    "timestamp": "消息时间"
  },
  "sign": "E9324CF02F95CB072B6DBCEA33E725C3"
}

字段说明

字段 类型 说明
data.id string 消息唯一ID
data.chat_id string 对话ID
data.chat_title string 对话名称
data.content string 消息内容
data.timestamp string 消息时间戳
sign string 请求签名(大写MD5)

3. 签名规则(如果需要)

3.1 生成规则

  1. data 中的参数按照 key=value 的形式组织,并 按字典序升序排序

  2. 示例:

    chat_id=123&chat_title=测试群&content=你好&id=abc123&timestamp=1724060800
    
  3. 在末尾拼接接口密钥:

stringSignTemp = 排序后的参数串 + "&key=接口方提供的密钥"
  1. 计算 MD5 值,并转为大写:
sign = MD5(stringSignTemp).toUpperCase()

3.2 示例

假设传入参数为:

{
  "id": "abc123",
  "chat_id": "123",
  "chat_title": "测试群",
  "content": "你好",
  "timestamp": "1724060800"
}

排序后:

chat_id=123&chat_title=测试群&content=你好&id=abc123&timestamp=1724060800

拼接密钥(假设key=192006250b4c09247ec02f6a2d):

chat_id=123&chat_title=测试群&content=你好&id=abc123&timestamp=1724060800&key=192006250b4c09247ec02f6a2d

计算MD5并转大写:

E9324CF02F95CB072B6DBCEA33E725C3

最终推送给服务端时:

{
  "data": {
    "id": "abc123",
    "chat_id": "123",
    "chat_title": "测试群",
    "content": "你好",
    "timestamp": "1724060800"
  },
  "sign": "E9324CF02F95CB072B6DBCEA33E725C3"
}

4. 服务端校验逻辑

服务端接收到请求后,需要做以下几步:

  1. 解析 datasign
  2. 按签名规则重新生成本地 sign
  3. 比较请求中携带的 sign 与本地生成的 sign 是否一致。

  4. 一致 → 验证通过,数据可信。

  5. 不一致 → 拒绝请求。

5. 响应格式

服务端返回示例:

{
  "code": 0,
  "msg": "success"
}
字段 类型 说明
code int 0 表示成功,其它表示失败
msg string 结果描述

服务端示例代码(Java、Python、PHP),都包含以下功能:

  1. 接收客户端推送的 JSON 请求;
  2. data 提取参数,按规则生成签名;
  3. 校验 sign 是否正确;
  4. 返回结果。

Java (Spring Boot 示例)

import org.springframework.web.bind.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.security.MessageDigest;
import java.util.*;

@RestController
public class PushController {

    private static final String KEY = "192006250b4c09247ec02f6a2d";

    @PostMapping("/push")
    public Map<String, Object> receivePush(@RequestBody Map<String, Object> body) {
        Map<String, Object> response = new HashMap<>();

        try {
            Map<String, Object> data = (Map<String, Object>) body.get("data");
            String clientSign = (String) body.get("sign");

            // 生成本地签名
            String localSign = generateSign(data);

            if (localSign.equals(clientSign)) {
                response.put("code", 0);
                response.put("msg", "success");
            } else {
                response.put("code", 1);
                response.put("msg", "invalid sign");
            }
        } catch (Exception e) {
            response.put("code", -1);
            response.put("msg", "error: " + e.getMessage());
        }

        return response;
    }

    private String generateSign(Map<String, Object> data) throws Exception {
        List<String> keys = new ArrayList<>(data.keySet());
        Collections.sort(keys);

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            sb.append(key).append("=").append(data.get(key)).append("&");
        }
        sb.append("key=").append(KEY);

        return md5(sb.toString()).toUpperCase();
    }

    private String md5(String input) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(input.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte b : array) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }
}

Python (Flask 示例)

from flask import Flask, request, jsonify
import hashlib

app = Flask(__name__)

KEY = "192006250b4c09247ec02f6a2d"

def generate_sign(data):
    # 排序参数
    items = sorted(data.items(), key=lambda x: x[0])
    query = "&".join(f"{k}={v}" for k, v in items)
    query = f"{query}&key={KEY}"

    md5 = hashlib.md5()
    md5.update(query.encode("utf-8"))
    return md5.hexdigest().upper()

@app.route("/push", methods=["POST"])
def push():
    try:
        body = request.json
        data = body.get("data", {})
        client_sign = body.get("sign", "")

        local_sign = generate_sign(data)

        if local_sign == client_sign:
            return jsonify({"code": 0, "msg": "success"})
        else:
            return jsonify({"code": 1, "msg": "invalid sign"})
    except Exception as e:
        return jsonify({"code": -1, "msg": f"error: {str(e)}"})

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

PHP 示例

<?php

$key = "192006250b4c09247ec02f6a2d";

function generateSign($data, $key) {
    ksort($data); // 按字典序排序
    $query = [];
    foreach ($data as $k => $v) {
        $query[] = $k . "=" . $v;
    }
    $queryStr = implode("&", $query) . "&key=" . $key;

    return strtoupper(md5($queryStr));
}

header("Content-Type: application/json");

// 读取请求体
$body = json_decode(file_get_contents("php://input"), true);

$data = $body["data"] ?? [];
$clientSign = $body["sign"] ?? "";

$localSign = generateSign($data, $key);

if ($localSign === $clientSign) {
    echo json_encode(["code" => 0, "msg" => "success"]);
} else {
    echo json_encode(["code" => 1, "msg" => "invalid sign"]);
}