908 words
5 minutes
Webhook 工作原理
Webhook 工作原理
本质
Webhook 就是一个 HTTP 回调:当 A 系统发生某件事时,A 主动发一个 HTTP POST 请求到 B 系统预先注册的 URL。
工作流程
B 系统注册回调 URL ──→ A 系统保存这个 URL
A 系统事件触发 ──→ HTTP POST ──→ B 系统接收处理(代码推送/支付完成等) (携带事件数据JSON)- 注册:你告诉 GitHub “当代码推送时,POST 到
https://ci.example.com/build” - 触发:有人 git push
- 推送:GitHub 向你的 URL 发送 POST,body 里是推送详情(JSON)
- 处理:你的 CI 服务器收到请求,开始构建
对比传统 API
| 传统 API | Webhook | |
|---|---|---|
| 模式 | 拉取(polling) | 推送(push) |
| 谁主动 | 客户端反复请求 | 服务端主动通知 |
| 实时性 | 取决于轮询频率 | 事件即触发 |
| 资源消耗 | 大量无效请求 | 只有事件时才发请求 |
典型场景
- GitHub → 代码推送后通知 CI/CD 构建
- 支付平台 → 交易完成后通知商户系统
- Slack/钉钉 → 机器人收到消息后触发自动化
- Kubernetes → Admission Webhook 拦截和校验请求
关键细节
- 幂等性:网络可能重传,接收方需要保证同一事件处理多次结果一致
- 签名验证:发送方通常用 HMAC 签名,接收方验证请求确实来自声称的源
- 重试机制:发送方在收到非 2xx 响应时,会按指数退避重试
本质上就是 发布-订阅模式的 HTTP 实现,把”订阅”简化为”注册一个 URL”。
服务端如何感知变化并推送
以 GitHub Webhook 为例,看完整链路。
注册阶段
你在 GitHub 仓库设置里填入:
- 回调 URL:
https://ci.example.com/build - 触发事件:
push - Secret:
my_secret_key
GitHub 把这些存到数据库。
事件触发
有人执行 git push,GitHub 收到代码后:
git push 到 GitHub │ ▼GitHub 处理完推送逻辑 │ ▼GitHub 查数据库:哪些 Webhook 订阅了 push 事件? │ ▼找到你的回调 URL │ ▼构造 HTTP POST 请求,body 是事件数据 (JSON) │ ▼用 Secret 计算 HMAC 签名,放在 Header 里 │ ▼发送 POST https://ci.example.com/build关键点:这里没有魔法,GitHub 的代码里就是硬编码了”完成 push 操作后,查 webhook 表,逐个发 HTTP 请求”。本质上是一个函数调用后触发的副作用。
# GitHub 内部伪代码def handle_git_push(repo, commits): # 1. 正常处理推送 save_commits(repo, commits) update_refs(repo)
# 2. 查询订阅了这个事件的 webhook webhooks = db.query("SELECT * FROM webhooks WHERE repo=? AND event='push'", repo)
# 3. 逐个推送 for hook in webhooks: payload = {"commits": commits, "repo": repo} signature = hmac_sign(payload, hook.secret) http_post(hook.url, payload, headers={"X-Hub-Signature": signature})接收端处理
你的 CI 服务器收到请求后:
# 你的服务器伪代码@app.post("/build")def on_push(request): # 1. 验证签名,确认是 GitHub 发的 verify_signature(request.body, request.headers["X-Hub-Signature"])
# 2. 解析事件数据 data = json.loads(request.body)
# 3. 执行业务逻辑 trigger_build(data["repo"], data["commits"])
# 4. 返回 200,告诉 GitHub "收到了" return Response(status=200)“HTTP 回调”是什么意思
回调这个概念来自编程:
# 编程里的回调def do_something(callback): result = work() callback(result) # 干完后调用你传进来的函数
do_something(my_handler) # 把 my_handler 作为回调传进去HTTP 回调就是把同样的思路搬到网络层面:
编程回调:把函数指针传过去,事件发生时调用你的函数HTTP 回调:把 URL 传过去,事件发生时向你的 URL 发 HTTP 请求- “回调 URL” = 你告诉对方”有事打这个电话”
- “HTTP 回调” = 对方通过 HTTP 请求”打这个电话”
Webhook 就是 HTTP 层面的回调函数,URL 就是指针,POST 请求就是函数调用。
Webhook 工作原理
https://sgjki547.top/posts/webhook-工作原理/