3.6.3 A/B 测试
A/B 测试
dwz-server 内置 A/B 测试能力,可以为同一短链接配置多个目标 URL,并按流量策略把访客分配到不同变体。A/B 测试不仅记录点击分流,还支持落地页或业务系统回传注册、下单、购买等业务结果,用于计算真实转化率和获胜变体。
模型
| 字段 | 说明 |
|---|---|
id |
A/B 测试 ID |
workspace_id |
所属工作区 ID |
short_link_id |
关联的短链接 ID |
name |
测试名称 |
description |
测试描述 |
status |
draft / running / paused / completed |
traffic_split |
流量分配策略:equal / weighted / custom |
start_time / end_time |
可选的开始与结束时间 |
variants |
变体数组,每个变体包含 name、target_url、weight、is_control、description |
生命周期
draft -> running -> [paused -> running] -> completeddraft:创建后的初始状态,不会影响线上跳转。running:对访客生效,按策略分流到变体目标 URL。paused:暂停分流,访问回退到短链接原始original_url。completed:终止测试,后续访问回退到短链接原始original_url。
已经跳转出去的用户可能延迟产生注册或订单,因此已完成或停止的实验仍接受未过期 _dwz_abt token 的转化反馈。
流量分配策略
equal
所有启用变体平均分配,适合最常见的 A/B 两分法。
weighted
按每个变体的 weight 比例分配流量。例如 A=70、B=30。
custom
保留给自定义分流策略。当前统计口径仍按最终命中的变体归集。
会话一致性
同一访客在实验期间会尽量保持命中同一变体。服务端会生成 A/B 会话 ID,并将点击记录归属到具体实验、变体、短链和工作区,避免同一个用户反复刷新时污染实验数据。
转化反馈
仅有点击数据无法判断业务结果。dwz-server 会在 A/B 跳转到变体目标 URL 时追加 _dwz_abt 查询参数:
https://example.com/page-a?_dwz_abt=<feedback_token>_dwz_abt 是服务端签名 token,绑定 workspace_id、ab_test_id、variant_id、short_link_id 和 session_id,默认有效期 30 天。直接访问变体目标 URL 不会生成 token,必须通过短链进入实验。
落地页或业务系统在产生注册、下单、购买等业务结果后,调用公开接口回传:
POST /api/v1/public/ab_test_feedback
Content-Type: application/json
{
"feedback_token": "<_dwz_abt 参数值>",
"event_id": "order-202401150001",
"value": 99.9,
"currency": "CNY",
"metadata": {
"plan": "pro"
}
}
event_id 在同一个 A/B 测试内幂等。重复提交会返回成功并标记 duplicate: true,但不会重复计入转化。
管理端 A/B 测试统计弹窗中的“分流反馈”区域仅用于手动验证。生产环境应由落地页或业务系统自动调用反馈接口。
统计口径
GET /api/v1/ab_tests/{id}/statistics 返回实验整体统计与变体统计。
常用字段:
| 字段 | 说明 |
|---|---|
total_clicks |
实验总点击数 |
total_conversions |
反馈接口记录的总转化数 |
conversion_value |
反馈事件 value 汇总 |
click_count |
单个变体点击次数 |
unique_clicks |
单个变体唯一会话点击数 |
conversion_count |
单个变体转化数 |
conversion_rate |
变体转化率:conversion_count / unique_clicks * 100 |
percentage |
变体点击占比 |
winning_variant |
当前按转化数最高计算的获胜变体 |
点击占比不等于转化率。真实转化率只来自业务反馈事件。
落地页回传示例
const token = new URLSearchParams(location.search).get('_dwz_abt');
if (token) {
await fetch('https://your-domain.com/api/v1/public/ab_test_feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
feedback_token: token,
event_id: 'order-202401150001',
value: 99.9,
currency: 'CNY',
metadata: {
order_id: '202401150001',
plan: 'pro'
}
})
});
}