DeckFlow Logo 开发者 DeckFlow 文档
开发者指南API 参考MCPCLI

Webhook / 异步任务与实时订阅

DeckFlow 异步任务模型、状态订阅方式(SSE 实时流与 API 轮询)及 Webhook 回调机制的优缺点与代码实现。

DeckFlow 的大多数文稿处理操作(包括生成、翻译、焕新以及文件转换)均属于计算密集型任务。为了保证接口的即时响应,DeckFlow 全面采用异步处理模型。

在提交任务(POST /tools/tasks)后,开发者可以通过三种不同的方式获取任务的最终结果:SSE 实时订阅 (Server-Sent Events)、定期轮询 (Polling) 和 Webhook 回调 (Webhook Callback)。


1. 状态获取方式对比

为方便开发者选择,以下为 SSE 实时流订阅与定期轮询两种主要拉取方式的优缺点对比:

获取方式推荐度优点缺点适用场景
SSE 实时流订阅 (Server-Sent Events)推荐 (Highly Recommended)实时性极高;轻量级且极省资源(单次 HTTP 连接);无需多次重复建连,服务端主动推送进度。客户端需支持流式响应解析;在长时间断网时需要自行实现重连逻辑。网页/客户端交互、CLI 自动化脚本、要求实时呈现进度的前后台交互。
API 定期轮询 (Polling)仅作为备用 / 降级方案实现简单,任何 HTTP 客户端均原生支持;对客户端环境无特殊流式处理要求。延迟较高;频繁请求会消耗大量网络带宽和服务器计算资源,极易触发 429 限流。简单后台定时任务、客户端无法维持长连接的受限环境。

2. 单步长连接实时订阅 (SSE)

当客户端向任务状态查询接口发送请求时,如果携带了特定的 HTTP 头部,DeckFlow 会自动将连接升级为 SSE 实时数据流。

接口规范

  • 请求路径:GET /tools/tasks/{taskId}
  • 关键请求头:response-event-stream: yes (必须设置为 yes 以启用 SSE 模式)

代码示例

  # 使用 curl 接收实时状态流推送
  curl -X GET "https://app.deckflow.com/api/tools/tasks/YOUR_TASK_ID" \
    -H "Authorization: Bearer <YOUR_API_KEY>" \
    -H "response-event-stream: yes"
  const taskId = "YOUR_TASK_ID";
  const url = `https://app.deckflow.com/api/tools/tasks/${taskId}`;

  async function subscribeTaskSSE() {
    const response = await fetch(url, {
      headers: {
        'Authorization': 'Bearer <YOUR_API_KEY>',
        'response-event-stream': 'yes'
      }
    });

    const reader = response.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      const lines = chunk.split('\n');

      for (const line of lines) {
        if (line.startsWith('data:')) {
          const task = JSON.parse(line.replace('data:', '').trim());
          console.log('收到实时进度推送:', task.status);

          if (task.status === 'completed') {
            console.log('任务已完成!下载链接:', task.result.url);
            return;
          } else if (task.status === 'failed') {
            console.error('任务处理失败,错误信息:', task.error);
            return;
          }
        }
      }
    }
  }

  subscribeTaskSSE();
  import requests, json

  task_id = "YOUR_TASK_ID"
  url = f"https://app.deckflow.com/api/tools/tasks/{task_id}"
  headers = {
      "Authorization": "Bearer <YOUR_API_KEY>",
      "response-event-stream": "yes"
  }

  def subscribe_task_sse():
      response = requests.get(url, headers=headers, stream=True)
      for line in response.iter_lines():
          if line:
              decoded_line = line.decode('utf-8')
              if decoded_line.startswith('data:'):
                  task = json.loads(decoded_line.replace('data:', '').strip())
                  print("收到实时进度推送:", task.get("status"))

                  if task.get("status") == "completed":
                      print("任务已完成!下载链接:", task["result"]["url"])
                      break
                  elif task.get("status") == "failed":
                      print("任务处理失败,错误信息:", task.get("error"))
                      break

  subscribe_task_sse()

3. 定期轮询机制 (Polling)

若采用轮询机制,客户端必须向状态查询接口发起多次独立的 HTTP 请求。

接口规范

  • 请求路径:GET /tools/tasks/{taskId}
  • 关键请求头:Authorization: Bearer <YOUR_API_KEY>

轮询实现建议

为避免触发服务器的并发限制(429 Rate Limit),请务必遵守以下原则:

  1. 指数退避:初始间隔可以设置在 3 秒左右。随着查询次数增加,应逐渐加大间隔(例如 3s -> 5s -> 10s -> 20s),直至任务结束。
  2. 硬性超时限制:建议根据任务文件大小设置最大轮询时长限制(如不超过 5 分钟),超时后标记为轮询终止或重试。

代码示例

  const taskId = "YOUR_TASK_ID";
  const url = `https://app.deckflow.com/api/tools/tasks/${taskId}`;
  const headers = { 'Authorization': 'Bearer <YOUR_API_KEY>' };

  async function pollTaskStatus() {
    let delay = 3000; // 初始延迟 3 秒
    const maxDelay = 30000; // 最大延迟 30 秒

    while (true) {
      const res = await fetch(url, { headers });
      const task = await res.json();
      console.log('轮询查询状态:', task.status);

      if (task.status === 'completed') {
        console.log('任务成功,结果下载链接:', task.result.url);
        break;
      } else if (task.status === 'failed') {
        console.error('任务失败,原因为:', task.error);
        break;
      }

      // 指数退避累加
      await new Promise(resolve => setTimeout(resolve, delay));
      delay = Math.min(delay * 1.5, maxDelay);
    }
  }

  pollTaskStatus();
  import requests, time

  task_id = "YOUR_TASK_ID"
  url = f"https://app.deckflow.com/api/tools/tasks/{task_id}"
  headers = { "Authorization": "Bearer <YOUR_API_KEY>" }

  def poll_task_status():
      delay = 3.0  # 初始 3 秒
      max_delay = 30.0

      while True:
          response = requests.get(url, headers=headers)
          task = response.json()
          status = task.get("status")
          print("轮询查询状态:", status)

          if status == "completed":
              print("任务成功,结果下载链接:", task["result"]["url"])
              break
          elif status == "failed":
              print("任务失败,原因为:", task.get("error"))
              break

          time.sleep(delay)
          delay = min(delay * 1.5, max_delay)

  poll_task_status()

4. Webhook 回调通知

在不想主动订阅或轮询的场景下(例如纯后端离线任务批量处理),DeckFlow 支持通过 HTTP 回调将状态直接推送至开发者的公开服务器。

配置方式

在提交任务(POST /tools/tasks)的 Form Data 中,传递 notifyURL 参数,内容为您能够接收 POST 请求的公网 HTTP 服务器端点。

回调触发与内容

当任务状态发生终态变化(变更为 completed 或 failed)时,DeckFlow 平台会自动发起一次 HTTP POST 请求。

  • 请求体格式:application/json
  • 请求体内容:完整的 Task 实体对象 JSON。

回调请求 JSON 示例:

{
  "id": "task-550e8400-e29b-41d4-a716-446655440000",
  "name": "Market Research Slide Revamp",
  "type": "revamp",
  "status": "completed",
  "result": {
    "url": "https://app.deckflow.com/download/processed-presentation.pptx?...",
    "mimeType": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
  },
  "createdAt": "2026-06-11T08:52:00.000Z",
  "updatedAt": "2026-06-11T08:54:15.000Z"
}