跳转至

WebHook 使用教程

适用场景

  • 它是什么: WebHook 是由 BizyAir 主动把 API 调用的任务结果以 HTTP POST 推送到你提供的回调 URL 的机制,省去你在客户端或服务端阻塞等待的麻烦。
  • 它能解决的问题: 把“等待结果”的责任从客户端移到后端;避免长时间占用连接;当任务完成时第一时间收到完整结果。

快速判断是否适合使用

  • 任务耗时较长,不想阻塞客户端等待
  • 希望在任务完成后由服务端异步处理
  • 能提供稳定、公网可达的回调地址(建议使用 HTTPS)

本教程将带你从零搭建一个可接收回调的服务,并通过设置 X-BizyAir-Task-WebHook-Url 以异步获得任务结果。你将能够:

  • 启用 WebHook 模式并拿到 requestId
  • 在自己的服务器上接收、验证并存储回调结果
  • 正确返回 200 以避免云端重复重试

前置准备

  • 已获取 BizyAir API Key( Authorization: Bearer {Your_ApiKey}
  • 一台 可以公网访问 的回调服务(示例以云服务器为例)
  • 可选:用于校验回调来源的回调 Token,例如 X-BizyAir-Task-Authorization: Bearer YOUR_CALLBACK_TOKEN

必须可公网访问并尽量使用 HTTPS

回调地址需要公网可达,且建议使用 https://,以确保数据在传输过程中被加密,避免被中间人篡改或窃取。

回调 Header 透传

任何以 X-Bizyair-Task- 为前缀的自定义 Header 会在回调中原样返回,可用于携带租户信息、签名等元数据。

步骤一:启动一个回调服务

你可以用任意后端框架,这里给出两种极简示例(任选其一)。

方案 A:Node.js(Express)

初始化 Node 服务
npm init -y && npm i express body-parser
server.js
// server.js
const express = require("express");
const bodyParser = require("body-parser");

const app = express();
app.use(bodyParser.json());

// 如果设置了 X-BizyAir-Task-Authorization: Bearer YOUR_CALLBACK_TOKEN
const EXPECTED_TOKEN = process.env.CALLBACK_TOKEN; // 可选

app.post("/api/callback", (req, res) => {
  const auth = req.get("Authorization");
  if (EXPECTED_TOKEN) {
    const ok =
      auth &&
      auth.startsWith("Bearer ") &&
      auth.split(" ")[1] === EXPECTED_TOKEN;
    if (!ok) return res.status(401).json({ message: "invalid callback token" });
  }

  const payload = req.body;
  // 这里进行幂等处理:依赖 payload.request_id 做去重
  // TODO: 将结果写入数据库/消息队列等
  console.log("Received callback:", payload);

  // 必须返回 200,避免重试
  res.status(200).json({ ok: true });
});

const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Callback server listening on :${port}`));

运行:

运行回调服务
CALLBACK_TOKEN=YOUR_CALLBACK_TOKEN node server.js

方案 B:Python(Flask)

安装 Flask
pip install flask
app.py
# app.py
import os
from flask import Flask, request, jsonify

app = Flask(__name__)
EXPECTED_TOKEN = os.getenv('CALLBACK_TOKEN')  # 可选

@app.post('/api/callback')
def callback():
    auth = request.headers.get('Authorization')
    if EXPECTED_TOKEN:
        ok = auth and auth.startswith('Bearer ') and auth.split(' ')[1] == EXPECTED_TOKEN
        if not ok:
            return jsonify({'message': 'invalid callback token'}), 401

    payload = request.get_json(silent=True) or {}
    # 幂等处理:用 payload.get('request_id') 做去重
    # TODO: 写入数据库/消息队列
    print('Received callback:', payload)

    # 必须返回 200
    return jsonify({'ok': True}), 200

if __name__ == '__main__':
    port = int(os.getenv('PORT', '3000'))
    app.run(host='0.0.0.0', port=port)

运行:

运行 Flask 回调服务
CALLBACK_TOKEN=YOUR_CALLBACK_TOKEN python app.py

步骤二:以 WebHook 模式发起任务

在原本的 API 请求 Headers 中加入 X-BizyAir-Task-WebHook-Url 即可启用异步回调:

以 WebHook 模式发起任务
# Shell 示例代码
curl -X POST "https://api.bizyair.cn/w/v1/webapp/task/openapi/create" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "X-BizyAir-Task-WebHook-Url: https://your-server.com/api/callback" \
  -H "X-BizyAir-Task-Authorization: Bearer YOUR_CALLBACK_TOKEN" \
  -d '{
  "web_app_id": 35661,
  "suppress_preview_output": false,
  "input_values": {
    "1:EmptyLatentImage.width": "1024",
    "1:EmptyLatentImage.height": "1024",
    "2:BizyAir_BasicScheduler.steps": "20",
    "3:BizyAir_RandomNoise.noise_seed": "1",
    "4:BizyAirSiliconCloudLLMAPI.user_prompt": "小猫,梵高风格",
    "4:BizyAirSiliconCloudLLMAPI.system_prompt": "你是一个 stable diffusion prompt 专家,为我生成适用于 Stable Diffusion 模型的prompt。 我给你相关的单词,你帮我扩写为适合 Stable Diffusion 文生图的 prompt。要求: 1. 英文输出 2. 除了 prompt 外,不要输出任何其它的信息 "
  }
}'

回调 URL 写法

  • X-BizyAir-Task-Authorization 为可选Headers
  • 如callback地址需要权限,可以通过 X-BizyAir-Task-Authorization 配置权限的请求头

成功后服务会立即返回 202 AcceptedrequestId

请求接受后的同步响应示例
1
2
3
{
  "requestId": "29f53793-12d3-4dd3-b2a8-4d9848e0c7da"
}

步骤三:接收回调与校验

在执行完工作流任务后 BizyAir 会回调之前请求中给出的 X-BizyAir-Task-WebHook-Url,发送任务执行的结果,回调的具体内容如下

  • 回调 Method:POST
  • 回调 Headers:Content-Type: application/json ,以及你在初始请求设置的 Authorization / 自定义 X-Bizyair-Task-*
  • 回调 Body(示例):
回调 Body 示例
{
  "type": "API",
  "status": "Success",
  "created_at": "2025-09-09 11:00:26",
  "updated_at": "2025-09-09 11:00:37",
  "executed_at": "2025-09-09 11:00:26",
  "running_at": "2025-09-09 11:00:26",
  "ended_at": "2025-09-09 11:00:37",
  "expired_at": "2025-09-24 00:00:00",
  "request_id": "29f53793-12d3-4dd3-b2a8-4d9848e0c7da",
  "outputs": [
    {
      "object_url": "https://storage.bizyair.cn/outputs/...",
      "output_ext": ".png",
      "cost_time": 10657,
      "audit_status": 2,
      "error_type": "NOT_ERROR"
    }
  ],
  "cost_times": {
    "inference_cost_time": 10670,
    "running_cost_time": 10956,
    "total_cost_time": 10965,
    "real_cpu_cost_time": 222,
    "real_total_cost_time": 9887,
    "real_bizyair_cost_time": 9665
  }
}

幂等与安全最佳实践

  • 使用 request_id 做幂等去重,避免重复入库或重复执行
  • 若设置了 X-BizyAir-Task-Authorization,在回调服务校验该 Token
  • 回调中如含产出物 object_url,请在有效期内尽快拉取并做好持久化

重试与应答要求

回调端务必在处理完成后返回 HTTP 200 OK。若返回非 200、超时或无响应,平台会按策略重试(约每 6 秒一次,最多 10 次)。

常见问题(FAQ)

为何收到多次相同回调?

你的服务未及时返回 200 OK 或超时,平台会按策略重试。请确保快速应答,并用 request_id 做幂等。

如何验证回调来源?

在初始请求中设置 X-BizyAir-Task-Authorization: Bearer <token>,并在回调服务中比对该 token 是否一致。

回调成功,但下载结果失败?

检查 outputs[].object_url 是否过期或访问受限;建议尽快拉取并持久化,避免链接过期导致下载失败。


相关参考


其他有关接口