You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为个人JavaScript/Node项目自定义开发Webhook功能?

核心原理澄清

你对Webhook的理解存在部分偏差:Webhook本质是服务端到服务端的单向回调机制,即外部服务处理完任务后,主动调用你提前提供的服务端接口通知结果,它本身不具备直接给客户端推送多次响应的能力。你理解的「客户端发一次请求就能接收服务端多次响应」是服务端与客户端之间的实时通信能力,和Webhook是两个独立的技术环节。

另外Webhook完全可以自定义开发,并非只能由第三方服务提供,你只需要在自己的服务端写一个可供外部服务调用的POST接口,这就是属于你的自定义Webhook。

业务流程完整实现方案

1. 开发服务端Webhook接口

这个接口就是你提供给外部API的回调地址,属于普通的Express POST接口,示例代码如下:

// Express 服务端代码
// 部署后你的Webhook地址为 https://你的域名/api/webhook/external-callback
app.post('/api/webhook/external-callback', express.json(), async (req, res) => {
  // 第一步:校验请求来源合法性,避免恶意请求(对接的外部API一般会提供签名校验规则)
  // const isValid = verifyExternalSignature(req);
  // if(!isValid) return res.sendStatus(403);

  const processedResult = req.body; // 外部API返回的处理结果
  // 存储结果到数据库
  await db.processedResults.insert(processedResult);
  // 必须给外部API返回200状态码,否则它会认为回调失败触发重试
  res.sendStatus(200);

  // 推送新结果到前端
  sendDataToClient(processedResult);

  // 检查是否还有未提交的待处理数据,有就提交下一批
  const nextBatch = await db.pendingData.takeBatch(10);
  if(nextBatch.length > 0) {
    await fetch('外部API提交地址', {
      method: 'POST',
      body: JSON.stringify(nextBatch),
      headers: { 'Content-Type': 'application/json' }
    })
  }
})

2. 搭建服务端到前端的实时推送通道

要实现服务端收到Webhook回调后主动推数据给前端,轻量方案可选SSE(服务器发送事件),符合你的单向多次推送需求,服务端实现示例:

// 存储所有已连接的客户端SSE响应对象
const connectedClients = new Map();

// SSE连接接口,前端页面加载时就发起连接
app.get('/api/realtime-stream', (req, res) => {
  // 设置SSE required响应头
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  // 生成当前客户端唯一标识
  const clientId = Date.now().toString();
  connectedClients.set(clientId, res);

  // 客户端断开连接时清理资源
  req.on('close', () => {
    connectedClients.delete(clientId);
  });
})

// Webhook回调里调用的推送方法
function sendDataToClient(data) {
  connectedClients.forEach((clientRes) => {
    // 按SSE规范格式发送数据
    clientRes.write(`data: ${JSON.stringify(data)}\n\n`);
  })
}

3. React前端逻辑实现

import { useEffect, useState } from 'react';

function DataPage() {
  const [allData, setAllData] = useState([]);

  useEffect(() => {
    // 页面加载时拉取初始数据
    fetch('/api/init-data')
      .then(res => res.json())
      .then(initData => setAllData(initData));

    // 建立SSE长连接接收推送
    const eventSource = new EventSource('/api/realtime-stream');
    eventSource.onmessage = (event) => {
      const newResult = JSON.parse(event.data);
      setAllData(prev => [...prev, newResult]);
    }

    // 组件卸载时关闭连接
    return () => eventSource.close();
  }, []);

  // 点击按钮触发第一批数据提交,用POST请求即可
  const handleStart = async () => {
    await fetch('/api/start-process', { method: 'POST' });
  }

  return (
    <div>
      <button onClick={handleStart}>开始批量处理</button>
      {allData.map(item => <div key={item.id}>{item.content}</div>)}
    </div>
  )
}
注意事项
  • Webhook接口一定要做请求来源校验,避免恶意请求篡改你的业务数据
  • 要做好回调结果去重,外部API在回调超时/失败时一般会触发重试,避免重复处理同一份结果
  • 如果你的服务端是多实例部署,需要搭配Redis发布订阅能力同步跨实例的推送消息,保证所有在线客户端都能收到数据

内容的提问来源于stack exchange,提问作者Franco Ortega

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:06:04