输入关键词搜索

回调签名与验签规范

更新时间: 2026/08/27 10:13:38

本文介绍业务方接收云信大模型 API(简称 AIHub)网关异步回调时的协议规范。

若底层模型供应商也使用回调签名,AIHub 会在网关侧完成供应商回调处理。业务方仅需按照本文校验 AIHub 发往 callback_url 的回调请求即可。

技术原理

业务方在创建异步任务时可以传入 callback_url。任务状态发生变化后,AIHub 向该地址发送回调通知,并使用创建任务时的访问令牌作为签名密钥,对请求方法、请求路径、时间戳、随机数和原始请求体摘要生成 HMAC-SHA256 签名。

业务方收到回调后,应使用同一访问令牌重新计算签名,并与请求头中的签名值进行常量时间比较。验签通过后,再处理回调体中的任务状态和生成物信息。

签名机制用于确认回调来源、发现请求体篡改,并配合时间戳和随机数降低重放风险。

回调请求规范

触发条件

  • 仅异步任务接口会触发业务方回调。
  • 创建任务时必须传入 callback_url,AIHub 才会发起回调。
  • 常见任务状态包括 processingsuccessfailed,具体字段以对应接口文档为准。

callback_url要求

规则 说明 失败错误
长度 不超过 512 个字符 callback_url_too_long
URL 结构 必须包含 scheme 和 host callback_url_invalid
用户信息 不允许包含 userinfo callback_url_invalid
协议 生产环境推荐并默认要求 HTTPS callback_url_scheme_forbidden
裸 IP 不得命中私网、回环、链路本地等地址 callback_url_private_ip

方法

httpPOST {user_callback_url}
Content-Type: application/json; charset=utf-8

业务方需返回 2xx 状态码表示接收成功。AIHub 不会跟随 3xx 跳转;如需迁移回调地址,请在创建任务时传入最终地址。

请求头

Header 示例值 说明
Content-Type application/json 回调请求体格式
X-AIHub-Timestamp 1776483051 Unix 秒级时间戳(UTC)
X-AIHub-Nonce 6cbf797d065943dff4eeaf18349e7934 随机字符串,用于辅助防重放
X-AIHub-Signature <64 位 hex> HMAC-SHA256 签名值(小写 hex)

请求体

回调体为 JSON,包含当前任务状态信息。业务方可读取以下字段:

字段 说明
task_id 任务 ID
state 任务状态(如 processingsuccessfailed
err_code 错误码(失败时返回)
credits 积分消耗,固定为 8 位小数字符串
creations 生成物列表

示例:

json{
  "task_id": "tsk_1234567890",
  "state": "success",
  "err_code": "",
  "credits": "50.00000000",
  "creations": [
    {
      "id": "creation_xxx",
      "url": "https://example.com/file.mp4"
    }
  ]
}

不同任务类型的生成物字段以对应接口文档和任务查询结果为准。验签时必须使用原始请求体字节计算摘要,不要先解析 JSON 后再重新序列化。

签名算法

secret

回调验签使用创建任务时的 AIHub 访问令牌明文作为 secret

textsecret = sk-xxxxx

string_to_sign

textHTTP_METHOD + "\n" +
REQUEST_URI + "\n" +
X-AIHub-Timestamp + "\n" +
X-AIHub-Nonce + "\n" +
sha256_hex(body)
组件 说明
HTTP_METHOD 固定为 POST
REQUEST_URI 业务方回调地址的 path + raw query(不含 scheme 和 host)
X-AIHub-Timestamp 请求头中的时间戳(Unix 秒字符串,不要重新格式化)
X-AIHub-Nonce 请求头中的随机字符串
sha256_hex(body) 原始请求体字节的 SHA-256 十六进制(小写)

REQUEST_URI 需保留原始 path 编码、query 顺序和 query 编码方式,不要 URL decode 后再拼接,也不要重新排序 query 参数。

signature

textsignature = hex(HMAC-SHA256(secret, string_to_sign))

最终签名值放入请求头 X-AIHub-Signature

验签步骤

  1. 读取原始 body 字节,不要预先解析或改写 JSON。
  2. 读取请求头: X-AIHub-TimestampX-AIHub-NonceX-AIHub-Signature
  3. 使用创建任务时的 sk-... 明文作为 secret
  4. 按签名算法重新计算签名。
  5. X-AIHub-Signature 进行常量时间比对。

建议附加校验:

  • X-AIHub-Timestamp 与本地时钟偏差在可接受窗口内(如 ±5 分钟)。
  • X-AIHub-Nonce 做重放保护(同一 nonce 在一定窗口内仅接受一次)。
  • task_id 应作为业务侧幂等键的一部分,避免重复回调导致重复处理。

Python 验签示例

pythonimport hashlib
import hmac
import time
from urllib.parse import urlparse

def verify_callback(
    secret: str,
    callback_url: str,
    method: str,
    timestamp: str,
    nonce: str,
    body: bytes,
    provided_sig: str,
    skew_seconds: int = 300,
) -> bool:
    # 1. 时间窗校验(强烈建议)
    try:
        ts = int(timestamp)
    except ValueError:
        return False
    if abs(int(time.time()) - ts) > skew_seconds:
        return False

    # 2. 构造 string_to_sign
    parsed = urlparse(callback_url)
    request_uri = parsed.path or "/"
    if parsed.query:
        request_uri += "?" + parsed.query

    body_sha = hashlib.sha256(body).hexdigest()
    string_to_sign = "\n".join([
        method.upper(),
        request_uri,
        timestamp,
        nonce,
        body_sha,
    ])

    # 3. 计算签名并进行常量时间比较
    expected = hmac.new(
        secret.encode("utf-8"),
        string_to_sign.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, provided_sig)

重试规则

默认重试退避策略:

text[0s, 10s, 60s]

处理规则:

  • 业务方返回任意 2xx:视为成功,不再重试
  • 业务方返回任意 4xx:视为最终失败,不再重试
  • 业务方返回 3xx5xx 或发生网络错误、超时:按退避策略继续重试
  • 重试耗尽后仍未成功:本次回调投递结束,业务方应通过任务查询接口兜底查询最终状态

重试耗尽后仍未成功,本次回调投递结束。业务方应通过任务查询接口兜底获取最终状态:

httpGET /hub/vidu/v2/tasks/{task_id}/creations

业务方处理回调时应保证幂等。对于同一个 task_id,以最新任务状态和生成物为准;若同时使用回调和主动查询,建议按任务终态做一次最终收敛。

此文档是否对你有帮助?
有帮助
去反馈
  • 技术原理
  • 回调请求规范
  • 触发条件
  • callback_url要求
  • 方法
  • 请求头
  • 请求体
  • 签名算法
  • secret
  • string_to_sign
  • signature
  • 验签步骤
  • Python 验签示例
  • 重试规则