引言
如果你曾经在两个服务之间搭建过集成——比如让一个系统的数据自动同步到CRM或Google表格中——你很可能已经接触过"Webhook"这个术语。这是当今自动化背后默默支撑一切的技术之一,从Slack通知到网店订单同步,几乎无处不在。 在这篇文章中,我们将用简单的语言解释什么是Webhook、它与普通API请求有何不同,以及如何在 Lix.li 中利用Webhook实际配置短链接点击通知。
用简单的话解释什么是Webhook
Webhook 是一种在特定事件发生的瞬间,自动将数据从一个服务传递到另一个服务的方式。你的系统不需要不断地问"有新内容出现了吗?",而是由服务本身在事件发生后立即将数据发送到你的服务器。 理解这个区别最简单的方式,是用寄信来打比方:
- 普通的API请求就像你自己反复跑到邮箱去看信有没有到。
- Webhook则像是订阅了配送服务:信件准备好之后,会自动送到你家门口。
从技术角度看,Webhook其实就是一个普通的HTTP请求(通常是
POST),当特定事件发生时——比如订单支付完成、任务状态发生变化,或者就 Lix.li 而言,某个短链接被点击——一台服务器会将请求发送到另一台服务器预先设置好的地址(URL)。
为什么需要Webhook
Webhook解决的是一个非常具体的问题:如何在不持续"轮询"(polling)外部服务的情况下,获取最新数据。 如果没有Webhook,想要知道有没有新事件发生,你就必须定期向API发送请求——每分钟一次,或者每五分钟一次——每次都要检查是否有新内容出现。这不仅给两端的服务器都带来了不必要的负担,而且事件发生的实际时间和你得知这一事件的时间之间,总会存在延迟。 Webhook把这个逻辑反过来了:服务会在事情发生时主动通知你。这对以下场景尤其有用:
- 自动化业务流程——例如,自动将新的销售线索录入CRM系统。
- 数据分析集成——将点击数据传输到你自己的数据统计系统。
- 机器人与通知——将事件发送给Telegram机器人或团队的Slack频道。
- 数据同步——实时更新Google表格、仪表盘或内部系统。
Webhook是如何工作的:以 Lix.li 为例
在 Lix.li 中,Webhook可以让你直接在自己的服务器上接收短链接点击数据——全程自动完成,无需不断轮询服务的API。如果你想把这些事件同步到CRM系统、数据分析系统、Google表格、Telegram机器人或任何其他自动化系统,这个功能会非常实用。
具体是如何构建的
- 点击数据不会逐条发送,而是先积累,再批量投递——每隔几分钟发送一次。这样能减轻你的服务器和 Lix.li 服务器双方的负担。
- 投递接近实时,但并非瞬时完成——Webhook适用于可以接受几分钟延迟的场景,而不是要求对每次点击都做出即时反应的场景。
- 投递保证遵循**"至少一次"**原则:如果发送过程中出现网络故障,同一批数据可能会被重复发送。因此每个事件都有一个唯一的
event_id,你应该在自己这一端根据它来去重。
在控制台中设置Webhook
Webhook功能面向 Premium 套餐用户开放。设置过程只需几个步骤:
- 在控制台中打开**"Webhook"部分,点击"添加"**。
- 填写以下内容:
- 接收地址(URL)——你服务器上用于接收请求的地址(例如
https://api.yoursite.com/webhooks/lix); - 作用范围——是针对所有链接发送事件,还是仅针对某个链接分组,或仅针对单条链接;
- 是否在事件数据中包含访客的IP地址(默认关闭,因为这属于个人数据)。
- 接收地址(URL)——你服务器上用于接收请求的地址(例如
- 创建Webhook后,系统会立即显示一个密钥(secret),该密钥仅显示一次——请务必保存好,它用于验证接收到的请求是否真实有效。
- 点击**"测试"**——服务会发送一条测试事件,并显示你的服务器是否正确响应。

你的服务器会收到什么内容
每个请求都通过 POST 方法发送,请求体格式为 application/json。除了数据本身之外,请求中还包含几个服务专用的请求头:
| 请求头 | 用途 |
|---|---|
X-Lix-Signature |
请求体的签名,格式为 sha256=——用于验证真实性。 |
X-Lix-Timestamp |
请求发送时间,以 Unix 时间戳表示。 |
X-Lix-Delivery |
本次投递的唯一标识符。 |
User-Agent |
固定值为 Lix-Webhooks/1.0。 |
| 请求体中包含具体的事件批次数据: |
{
"delivery_id": "0f3b9c2e-6a1d-4e88-9d5a-2f8c1b7a4e10",
"event_type": "redirects.batch",
"sent_at": "2026-06-01T12:05:00Z",
"window": {
"from": "2026-06-01T12:00:00Z",
"to": "2026-06-01T12:03:30Z"
},
"count": 2,
"truncated": false,
"events": [
{
"event_id": "2ef7bde608ce5404e97d5f042f95f89f1c232871",
"link_id": 12345,
"datetime": "2026-06-01T12:01:00Z",
"country": "US",
"city": "Boston",
"browser": "Chrome",
"os": "Windows",
"device": "Desktop",
"ref_domain": "google.com",
"group_id": null,
"is_bot": false
}
]
}
批次中的每个事件都包含链接ID、点击时间(UTC)、国家、城市、浏览器、操作系统、设备类型、点击来源域名、分组ID(如果已设置),以及是否为机器人访问的标记。访客的IP地址只有在你设置Webhook时明确启用该选项后,才会包含在数据中。
如果某个时间段内积累的事件数量过多,该批次可能会被标记为 truncated: true——这意味着部分数据将在下一次投递中送达,不会有任何数据丢失。
如何验证请求的真实性
由于你服务器的URL在技术上可能收到来自任何地方的请求,因此确认请求确实来自 Lix.li、而非伪造,是非常重要的一步。这正是 X-Lix-Signature 请求头中签名的作用。
验证原理如下:获取请求的"原始"(未经处理的)请求体,使用你的密钥计算其 HMAC-SHA256 值,再与请求头中携带的值进行比对。比较过程应采用安全的方式(恒定时间比较),以防止基于比较耗时的攻击。
PHP 示例:
$raw = file_get_contents('php://input');
$secret = 'your_secret';
$expected = 'sha256=' . hash_hmac('sha256', $raw, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_LIX_SIGNATURE'] ?? '')) {
http_response_code(401);
exit;
}
Node.js(Express)示例:
const crypto = require('crypto');
// 重要:必须获取原始请求体: app.use(express.raw({ type: 'application/json' }))
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(req.body).digest('hex');
const got = req.header('X-Lix-Signature') || '';
if (expected.length !== got.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
return res.sendStatus(401);
}
Python(Flask)示例:
import hmac, hashlib
raw = request.get_data() # 原始字节数据
expected = 'sha256=' + hmac.new(secret.encode(), raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get('X-Lix-Signature', '')):
return '', 401
对接收服务器的要求
为了让Webhook稳定运行,你的服务器需要满足以下几条规则:
- **返回
2xx状态码。**任何其他状态码,或者请求超时,都会被视为失败,系统将重新投递该批次。 - **快速响应。**你只有几秒钟的时间来响应——不要在请求处理函数中同步处理数据。正确的做法是:先快速保存收到的数据(例如存入队列或数据库),返回
2xx,然后再单独进行后续处理。 - **根据
event_id去重。**由于重试机制的存在,同一个事件有时可能会被发送两次。 - **保证幂等性。**重复处理同一批数据不应导致你这一端的数据出错。
- 对每一个收到的请求都进行签名验证。
- **使用 HTTPS。**不支持使用本地地址或内网地址来接收Webhook。
出现故障时会发生什么
如果你的服务器没有返回 2xx 状态码,Lix.li 会以逐渐增加的间隔时间重试投递。如果接收端长时间完全没有响应(连续多次失败),该Webhook会被自动暂停,以避免继续无意义地发送数据。这一情况会显示在控制台的投递日志中,待你修复接收端的问题后,即可重新启用该Webhook。
在控制台中管理Webhook
对于每个已配置的Webhook,你可以执行以下操作:
- 测试——发送一条测试事件,立即查看结果:成功,或返回你服务器具体的响应状态码。
- 暂停 / 恢复——临时停止或恢复事件的投递。
- 更换密钥——生成新的密钥以替换旧密钥;旧密钥会立即失效,因此务必同时在你自己的系统中更新密钥。
- 删除——彻底移除该Webhook。
- 投递日志——查看近期投递记录,包括状态、HTTP响应码、批次中的事件数量以及发送时间。
常见问题
事件多快能送达?
以批次形式送达,大约每隔几分钟一次,并有少量处理延迟。这并非即时推送,而是接近实时的场景。
同一个事件会不会被送达两次?
会,如果在网络故障后进行了重试投递。正因如此,务必在你这一端根据 event_id 字段对事件进行去重。
能否保证事件的严格顺序?
在同一个批次内,事件按照时间顺序排列,但不同批次之间不保证严格的全局顺序——建议依据每个事件的 datetime 字段进行排序。
流量非常大的时候会怎样?
如果某个时间段内积累的事件数量过多,该批次会被标记为 truncated: true,剩余部分会在下一次投递中送达——整个过程中不会丢失任何数据。
是否必须使用HTTPS?
是的,接收地址必须以 https:// 开头。系统不接受本地地址或内网地址。
能否只接收某一条链接或某个链接分组的事件?
可以。在创建Webhook时,你可以选择"单条链接"或"分组"作为作用范围,而不是账户下的全部链接。
一个完整的PHP处理示例
下面是一个简洁但可用的处理示例,它会验证签名、快速响应,并在处理事件时做好去重防护: