广告总被拒?聊聊广告斗篷系统(Cloaking)是怎么回事
广告总被拒?聊聊广告斗篷系统(Cloaking)是怎么回事
做广告投放的朋友应该都遇到过这种情况:
落地页辛辛苦苦做出来,刚投出去 —— 审核不通过。
改一版合规的 —— 通过了,但转化率惨不忍睹。
想让审核看到合规页,让真实用户看到转化页 —— 这就是「斗篷系统」要解决的问题。
今天就从技术角度聊聊这个东西到底是怎么回事。
一、什么是斗篷系统(Cloaking)
斗篷系统(Cloak / Cloaking)是一种访问识别与内容分流技术。
核心思路很简单:同一个 URL,根据访问者身份返回不同内容。
| 访问者 | 返回页面 |
|---|---|
| 广告审核蜘蛛 | 白页(合规内容) |
| 搜索引擎爬虫 | 白页(防止被索引) |
| 云服务 / VPN 流量 | 白页(屏蔽机房探测) |
| 真实用户 | 落地页(转化内容) |
关键点:URL 始终不变。审核看到的是合规页,真实用户看到的是转化页,两套内容互不干扰。
二、最简单的实现长什么样
网上很多教程,核心代码其实就这么点:
<?php
function detectBot(): bool {
$bots = ['googlebot', 'bingbot', 'facebookexternalhit', 'crawler', 'spider', 'bot'];
$userAgent = strtolower($_SERVER['HTTP_USER_AGENT'] ?? '');
foreach ($bots as $bot) {
if (strpos($userAgent, $bot) !== false) {
return true;
}
}
return false;
}
if (detectBot()) {
include "white_page.html"; // 审核看到
} else {
include "landing_page.html"; // 真实用户看到
}
问题来了:这种实现真的能用吗?
答案是:能跑,但生产环境完全不够用。
- 审核蜘蛛 UA 可以伪造
- 机房流量 UA 可以伪装成浏览器
- 代理 / VPN 流量无法识别
- 地域投放无法实现
- 桌面/移动分流缺失
于是就有了「生产级」的斗篷系统。
三、生产级系统:六层检测链路
真正能扛住线上流量的斗篷系统,通常是多层独立、可叠加的检测链路。任一层命中即返回白页,全部通过才返回落地页。
检测顺序(很关键)
访客请求
↓
1. 指纹检测(优先,识别自动化工具)
↓ 通过
2. ASN 黑名单(封云服务/VPN 提供商)
↓ 通过
3. 代理 / VPN 识别
↓ 通过
4. 城市检测(多 API 冗余)
↓ 通过
5. 设备控制(桌面/移动分流)
↓ 通过
6. 推广时间窗
↓ 通过
返回落地页
为什么要这个顺序?
指纹检测必须最先跑 —— 在查 ASN、查代理之前,先用指纹识别无头浏览器、自动化工具,性价比最高。
城市检测要放后面 —— 因为它依赖外部 API,慢且可能失败,放后面可以减少不必要的调用。
时间窗最后 —— 纯本地判断,最快,但优先级最低。
主流程代码(脱敏示例)
<?php
// 0. 获取真实 IP(CDN 反代场景)
$realIp = $_SERVER['HTTP_CF_CONNECTING_IP']
?? $_SERVER['HTTP_X_FORWARDED_FOR']
?? $_SERVER['REMOTE_ADDR'];
// 1. 指纹检测
if (detectFingerprint($_SERVER, $_COOKIE)) { serveWhitePage(); exit; }
// 2. ASN 黑名单
if (in_array(queryAsnByIp($realIp), getAsnBlacklist(), true)) {
serveWhitePage(); exit;
}
// 3. 代理识别
if (isProxyIp($realIp)) { serveWhitePage(); exit; }
// 4. 城市检测(失败默认放行,避免误拦截)
$city = detectCityRedundant($realIp);
if ($city !== '' && !isCityAllowed($city)) { serveWhitePage(); exit; }
// 5. 设备控制
$isMobile = isMobileDevice($_SERVER['HTTP_USER_AGENT']);
if (isDesktopRuleEnabled() && !$isMobile) { serveWhitePage(); exit; }
// 6. 时间窗
if (!isWithinPromotionTime()) { serveWhitePage(); exit; }
// 全部通过 → 落地页
serveLandingPage($isMobile);
四、几个容易被忽略的工程细节
1. 城市检测的正则陷阱
很多人写城市匹配会这样:
// ❌ 错误:会截断「广州」为「广」
$city = preg_replace('/[省市自治区]$/', '', $city);
正确写法是用分组:
// ✅ 正确:分组后缀匹配
$city = preg_replace('/(省|市|自治区)$/', '', $city);
2. 多 API 冗余的降级策略
城市检测不能只依赖一家 API,一旦挂了全站拦截就废了。生产做法是多家冗余:
$providers = ['provider_a', 'provider_b', 'provider_c', 'provider_d'];
foreach ($providers as $fn) {
try {
$city = $fn($ip);
if ($city) return normalizeCity($city);
} catch (Throwable $e) {
continue; // 单家失败不影响整体
}
}
return ''; // 全部失败 → 返回空 → 主流程默认放行
核心原则:宁可放过,不可误杀。全部 API 挂了就放行,别把真实用户挡在门外。
3. 推广时间窗的占位值
很多系统用 00:00:00 作为「不限制」的占位值。如果不处理,会出现零时长窗口的 bug:
// ✅ 占位值视为不限制
if ($start === '00:00:00' && $end === '00:00:00') {
return true;
}
4. 双缓存分发
落地页不能每次实时抓取,要做桌面/移动双缓存:
| 缓存文件 | 抓取环境 | 触发条件 |
|---|---|---|
{url}.html |
桌面 UA + 桌面分辨率 | 桌面访客 |
{url}_m.html |
移动 UA + 移动分辨率 | 移动访客 |
移动端缓存缺失时回退桌面缓存,避免移动用户看到空白页。
五、安全方面要注意什么
生产环境踩过的坑:
- PHP 错误显示必须关掉,否则错误信息会污染 JSON 响应,前端直接崩
- 长任务要异步收尾,否则主机面板 API 调用会把客户端拖超时
- 定时任务要用 Web 服务器用户跑,别用 root,否则会话文件归属错乱
- CDN 场景下要取真实 IP 头,否则你拦截的全是 CDN 节点 IP
- HTTPS 强制跳转不能删,SEO 和安全都需要
六、子站点架构(企业版场景)
如果你做的是 SaaS,让每个企业客户有自己的独立后台,就会涉及子站点架构:
- 子站点配置要 AES 加密存储,不能明文
- 主站与子站点的字段映射要统一(落地页/跳走页对应关系一致)
- 删除路由时顺序很重要:先清理主机面板站点 → 再删路由规则 → 再删路由链接 → 最后删主记录
- 企业版才显示独立后台按钮,基础版/专业版隐藏
七、关于「能不能用开源版」
GitHub 上有不少斗篷系统的开源示例,包括我自己也维护了一个:
但说实话,开源版只能用来学习原理,真正线上投放有几个硬伤:
- 指纹库需要持续维护,开源版没人更新
- ASN 黑名单需要定期同步,云厂商新增段很快
- 代理识别 API 要花钱,免费的不靠谱
- 多 API 冗余要申请多家 Key,配置繁琐
- 缓存抓取的弹窗清理、DOM 稳定性检测,工程量很大
如果你只是想了解原理,看开源代码完全够。如果是要真投广告、扛线上流量,建议直接用生产级系统,省下来的时间用来优化投放策略更划算。我这边做了一套生产级实现:abcloakpro.com,六层检测 + 双缓存 + 子站点独立后台,可以直接试用。
八、写在最后
斗篷系统本质上是访问者身份识别 + 内容分发,技术本身不复杂,复杂的是工程细节:
- 怎么让检测又快又准
- 怎么避免误杀真实用户
- 怎么应对审核规则变化
- 怎么让缓存稳定不空窗
这些细节决定了系统是「能跑」还是「能用」。
如果你也在做广告投放,欢迎评论区交流。需要生产级系统的可以看看我做的:abcloakpro.com,六层检测 + 双缓存 + 子站点独立后台,开箱即用。
本文代码已脱敏处理,完整项目地址:https://github.com/abcloakpro/Cloak-System
浙公网安备 33010602011771号