ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

域名防红跳转源码拆解:域名池、随机跳转与防屏蔽实战

域名防红跳转源码拆解:域名池、随机跳转与防屏蔽实战 简介一套带后台的域名防红跳转源码适用于网络推广与落地页运营人员通过两次随机跳转机制降低推广域名被平台屏蔽的风险。源码支持添加多个中转域名与跳转显示域名当某一域名被屏蔽时随机规则仍有机会让用户跳转至真实链接尤其适合微信等敏感渠道的推广场景。压缩包共10个文件含4个PHP脚本负责跳转逻辑、后台管理及数据库配置、SQL导入文件、CSS/JS样式脚本和说明页面整体约20.51MB部署需配合MySQL5.6/5.7与PHP7.2环境。后台可动态维护域名池无需每次修改代码便于批量推广与快速替换异常域名包内附有搭建说明与后台使用指引后台入口为admin.php无账号密码限制可快速完成域名配置。已有109人学习下载适合具备基础建站能力的用户按教程部署使用。1. 域名防红跳转源码把「链接被盾」变成后台里的一条记录做过投放或者内容分发的人大概率都经历过这种事昨天还好好的落地页链接今天打开就变空白页连带着整个渠道的转化全部归零。问题不在服务器而是域名被平台侧拦了。这套域名防红跳转源码核心就是解决这个事的——它把「单条链接裸奔」改成「一个入口 一个域名池 一套跳转策略」。访客访问入口地址后端从池子里挑一条当下有效的域名跳过去某条域名被盾后台把它停用流量自动切到别的域名。它自带后台管理、随机跳转、域名有效性检测适合手里有多个域名、做推广落地页分发、又被平台误拦搞怕了的从业者。我自己拆完的感受是这源码不大但把链接治理这件事从「玄学」变成了「可配置、可观测、可干预」。2. 先看懂这套跳转系统的骨架后台、跳转入口与检测脚本拿到源码第一件事不是急着部署而是把它的运行链路捋清楚。这套系统本质上是三层后台管理、跳转入口、检测脚本。三层各干各的又共用同一张域名池表。2.1 后台登录与域名池一个 URL 对应一条「策略」后台是一个典型的 PHP 管理界面登录后能看到域名池管理、跳转记录、系统设置。域名池是核心它并不只是一个 URL 列表每条记录还带着跳转策略的参数。我拆的时候把表结构梳理了一遍核心字段大概是这样字段作用说明id主键自增name备注名方便识别比如「落地页A」original_url原始落地地址用户最终到达的 URLshort_url生成的跳转入口对外分发的短地址target_domain目标域名实际被访问的域名域名池里的每一条weight权重随机跳转时的分配比例status启用状态1 启用 / 0 停用last_check_time最后检测时间检测脚本每次执行后更新check_result检测结果记录返回码和耗时后台的逻辑很简单添加域名、设权重、启停用、看记录。但真正影响线上表现的是两个隐藏逻辑——随机跳转怎么选目标以及失效域名怎么被自动发现。这两块分别对应跳转入口和检测脚本。2.2 跳转入口原理从 302 到 JS 跳转的取舍跳转入口是访客直接打交道的那一层。这套源码的典型处理方式是入口 URL 指向一个go.php或者伪静态后的地址后端拿到请求后从启用的域名池里选出一条 target_domain然后做 302 跳转。302 的优点是快后端返回一个 Location 头浏览器直接去目标地址整个过程几十毫秒。缺点是它对服务端日志和平台检测都比较「透明」。很多做链接治理的人会在这个环节换用 JS 跳转——先返回一个空页面页面里用window.location.replace()延迟几百毫秒再跳。这样做的好处是跳转行为更接近真实用户访问减少被脚本化误判的概率代价是多一跳用户会看到一瞬间的白屏。这套源码两种模式都带配置项里一般有一个jump_mode参数1是 3022是 JS。我建议线上优先用 JS 模式除非是短信场景对跳转速度要求极高。原因后面第 4 章会展开讲。2.3 有效性检测脚本你的域名池里有没有「僵尸链接」这是整套系统里最容易被忽略、但决定生死的一块。域名池里挂着 20 条域名你以为都是活的实际上可能已经挂了 7 条。检测脚本的作用就是定时去请求每一条 target_domain看返回码、看耗时、看响应内容然后把结果写回last_check_time和check_result。常见做法是用服务器 crontab 每 10 分钟跑一次检测 PHP 脚本脚本里用curl请求目标域名判断状态码是不是 2xx/3xx。我只判断状态码还不一定够——有些域名被拦的时候会返回 200 但内容是一个空白页或者验证页。所以脚本里最好再加一道「内容关键词」校验比如请求返回的 HTML 长度低于阈值或者包含某些特征字符串直接判定为失效。*/10 * * * * /usr/bin/php /var/www/html/check_domains.php /var/log/domain_check.log 21这段定时任务的意思是每 10 分钟跑一次检测脚本并把输出追加到日志文件里。参数说明*/10是 crontab 的分钟匹配写法表示每 10 分钟触发一次日志文件记得要提前创建并写好权限否则 cron 出错时你一点线索都看不到。3. 本地部署跑通环境、建库、配参数3.1 环境要求与目录结构这套源码对运行环境要求不高LNMP 或者 LAMP 都行。我拆的时候用的是 Nginx PHP 7.4 MySQL 5.7全程没遇到兼容性问题。目录结构大致如下/var/www/html/ ├── admin/ # 后台管理目录 │ ├── login.php # 后台登录页 │ ├── index.php # 后台首页 │ └── config.php # 后台连接配置 ├── go.php # 跳转入口 ├── check_domains.php # 域名检测脚本 ├── config.php # 公共配置数据库连接 ├── jump.js # JS 跳转模板 └── install.sql # 初始化数据库脚本环境方面有一个容易踩的配置PHP 需要开启curl扩展检测脚本依赖它还需要开启pdo_mysql所有数据库操作都走 PDO。如果你用的是宝塔面板在软件商店里把 PHP 扩展勾上即可。3.2 导入数据库并配置后台连接先把初始化脚本导入。在 MySQL 里新建一个库然后导入install.sql完成后能看到domain_pool、jump_log、admin_user这三张表。jump_log表是跳转记录每来一次请求就插一条。这个表在生产环境增长很快后面第 6 章会专门讲怎么用它反推跳转策略。CREATE DATABASE IF NOT EXISTS redirect_sys DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE redirect_sys; SOURCE /var/www/html/install.sql;这段 SQL 做了两件事创建一个名为redirect_sys的库字符集指定为utf8mb4然后执行导入文件建表。参数说明建库时指定utf8mb4是为了避免中文乱码这个库里的域名备注名、跳转记录都可能带中文用默认latin1的话后台会显示成问号。然后改config.php把数据库连接参数换成你自己的。唯一要注意的是端口——如果 MySQL 不是默认 3306必须在 DSN 里写清楚不然报could not find driver或者连接超时你会排查半天。?php define(DB_HOST, 127.0.0.1); define(DB_PORT, 3306); define(DB_NAME, redirect_sys); define(DB_USER, redirect_user); define(DB_PASS, 你的密码); define(DB_CHARSET, utf8mb4); $dsn sprintf(mysql:host%s;port%s;dbname%s;charset%s, DB_HOST, DB_PORT, DB_NAME, DB_CHARSET); try { $pdo new PDO($dsn, DB_USER, DB_PASS, [ PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE PDO::FETCH_ASSOC, ]); } catch (PDOException $e) { exit(数据库连接失败: . $e-getMessage()); }这段代码是公共配置文件里的核心逻辑用PDO连接 MySQL并设置了出错即抛异常和默认关联数组返回。参数说明PDO::ATTR_ERRMODE PDO::ERRMODE_EXCEPTION意味着 SQL 执行出错会直接抛异常方便你看到具体错误如果你习惯用数组下标访问PDO::FETCH_ASSOC就是需要的。3.3 配置伪静态与第一个跳转链接后台能登录之后下一步是添加第一条跳转记录。在后台「域名管理」里填 target_domain、原始落地页、权重保存然后你会得到一个跳转入口地址。这时候访问入口大概率 404——原因基本是伪静态没配。跳转入口通常不是go.php?id1这种带参数的形式而是go/abc123这种短地址。短地址好看、也好记但依赖 Web 服务器做 rewrite。Nginx 的配置写法location /go { rewrite ^/go/([a-zA-Z0-9])$ /go.php?code$1 last; } location /admin { try_files $uri $uri/ /admin/index.php?$query_string; }这段配置把/go/xxxx重写到go.php?codexxxx把/admin下的请求交给后台入口。参数说明last表示重写后重新匹配 location用break也可以但不会重新走其他 location 规则遇到后面要加鉴权、限流的时候会有差别建议用last。配好之后访问跳转地址按 F12 看 Network 面板能看到请求从go/abc123302 到了你的目标域名说明整条链路已经通了。4. 随机跳转与防屏蔽策略权重、保底与参数伪装这一章的配置决定了你这套跳转系统能撑多久不被平台盯上。很多新手把域名池填满就以为完事了结果跑了一天全被盾原因就是跳转策略太死板。4.1 随机跳转的三种实现完全随机、加权随机、轮询这套源码支持三种分配策略后台一个参数切过去就行。完全随机最简单每次从状态为启用的域名里随机取一条。好处是实现零成本坏处是热门落地页和冷门落地页被均匀分配浪费了高权重域名的流量价值。加权随机才是实战主力。每条域名设一个 weight 字段比如域名 A 权重 50、域名 B 权重 30、域名 C 权重 20分配比例就是 50% / 30% / 20%。实现逻辑不复杂但很多人在写 SQL 时容易犯一个错用ORDER BY RAND()加LIMIT 1做加权这是不对的RAND()完全随机weight 根本不管用。正确的做法是先查出所有启用域名和权重在 PHP 里按权重区间做抽取。function get_weighted_random_domain(PDO $pdo): array { $stmt $pdo-query(SELECT id, target_domain, weight FROM domain_pool WHERE status 1 ORDER BY id ASC); $domains $stmt-fetchAll(); if (empty($domains)) { throw new RuntimeException(域名池为空请先在后台添加启用域名); } $totalWeight 0; foreach ($domains as $d) { $totalWeight (int)$d[weight]; } $rand mt_rand(1, $totalWeight); $cursor 0; foreach ($domains as $d) { $cursor (int)$d[weight]; if ($rand $cursor) { return $d; } } return $domains[0]; }这段函数是加权随机的标准写法先算出所有域名权重的总和再生成一个1到总权重之间的随机数然后按顺序累加权重随机数落在哪一段就选哪条域名。参数说明mt_rand是 PHP 的梅森旋转随机数生成器比旧版rand分布更均匀抽选域名这种场景足够用ORDER BY id ASC保证每次查询顺序稳定选出来的结果可预期。轮询策略适合想控量的场景。每条域名记一个visit_count每次跳转时按访问次数排序选访问次数最少的域名。这个策略的缺点是瞬时流量大的时候可能同一秒内大量请求都打到同一条域名上需要配合缓存做原子自增否则并发下计数不准。我个人建议主力用加权随机轮询只在小流量测试时用。4.2 参数伪装cookie 记忆、来源判断与 UA 头随机跳转不能解决体验问题。用户第一次来跳到域名 A第二次来跳到域名 B第三次跳到域名 C——虽然每条域名都活着但用户会觉得你的链接「不稳定」。解决方式是 cookie 记忆同一个人访问过之后下次优先分配同一条域名只有它失效时才换。还有一个隐蔽的细节是 URL 参数。跳转之后的落地链接如果完全一样平台侧可以做聚合分析。比较稳的做法是给不同的域名分配不同的落地 URL 后缀比如在目标地址上拼一个随机 token 或者渠道参数。这套源码里能不能改取决于落地页端是否支持忽略多余参数如果不支持谨慎使用。来源判断也是必要的。移动端和 PC 端分配不同的落地页是很常见的需求。在跳转入口处检测 UA再根据设备类型去域名池里筛目标域名。function detect_device_type(string $userAgent): string { if (preg_match(/Mobile|Android|iPhone|iPad/i, $userAgent)) { return mobile; } return pc; }这段函数通过正则匹配 UA 字符串判断设备类型。说明一下preg_match的第二个参数是 UA匹配到Mobile、Android、iPhone这些关键词就返回mobile否则返回pc。拿到设备类型后在查域名池的 SQL 里加一个WHERE device_type :device条件即可。这里有个坑很多安卓平板的 UA 也带 Mobile会被误判成手机如果你有平板专属落地页需求需要单独加规则。4.3 保底机制跳转失败怎么兜一条活链接随机跳转做得再漂亮也会遇到目标域名刚好在你检测周期之间失效的情况。这个窗口期里用户访问过来会直接白屏。所以需要保底机制。后端保底做法是第一次选出来的域名不要直接用而是先选出 3 条域名主域名失效时自动切到下一条。但后端保底做不到「实时探测」因为每次跳转都去 curl 一遍目标域名响应时间会拖到几百毫秒影响体验。更实用的保底是 JS 前端兜底。跳转页面先输出一段 JS尝试跳转到主域名并且监听加载失败事件失败后换成备用域名。(function() { var primary https://domain-a.com/landing; var fallback https://domain-b.com/landing; var timer null; var fired false; function go(url) { if (fired) return; fired true; clearTimeout(timer); window.location.replace(url); } timer setTimeout(function() { go(primary); }, 500); window.addEventListener(pagehide, function() { clearTimeout(timer); }); })();这段 JS 的逻辑是延迟 500 毫秒后跳转主域名如果页面在跳转前被关闭pagehide事件清掉定时器避免用户明明已经离开还强行跳走。参数说明500毫秒是给浏览器预留的加载窗口太短可能出现主域名还没建立连接就超时太长用户感知到白屏pagehide是比unload更现代的事件移动端兼容性更好。备用域名的切换靠window.location.replace它会替换当前历史记录用户按返回键不会退回到一个空白页。这个机制的实际效果是即使主域名失效用户最多等 500 毫秒 一次 DNS 解析时间就能落到备用域名上不会被盾住。5. 部署避坑最容易翻车的五个细节我把这套源码从下载到上线完整走了一遍期间踩了 5 个问题全部记录如下每条都按「现象 → 原因 → 解决」拆开。坑一访问跳转链接直接 404现象后台能登录域名池里也添加了记录但访问go/xxxx返回 404不是 Nginx 默认页就是index.php内容。原因伪静态 rewrite 没生效。最常见的情况是 Nginx 配置里没有 include 站点的 rewrite 规则或者 rewrite 写到了location /而不是location /go。解决先访问go.php?codexxxx如果能跳转说明是 rewrite 的问题。把第 3.3 节的 Nginx 配置贴进去nginx -t检查语法后 reload。如果还不行确认你改的是当前站点监听的 server 块而不是默认配置文件。坑二后台中文乱码现象后台域名备注名和跳转记录里的渠道参数显示成???或乱码。原因建库时没指定 utf8mb4。很多人用面板创建数据库时用了默认字符集导入 SQL 时表结构是 utf8但库入口是 latin1连接层就转了码。解决重新按 3.2 节的 DDL 建库或者在已建库上执行ALTER DATABASE redirect_sys CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;并确认config.php里DB_CHARSET是 utf8mb4。改完重启 PHP-FPM。坑三随机跳转经常命中失效域名现象日志显示跳转记录不少但用户反馈经常白屏。原因检测脚本没跑起来或者脚本检测逻辑只看了 HTTP 状态码。域名被盾时经常返回 200 但页面是空的状态码检查根本发现不了。解决先手动执行php check_domains.php看检测日志写了什么然后给检测脚本加上「响应头 内容长度 关键词」三重校验。响应体长度小于 200 字节直接判死。另外确认 crontab 里写的是/usr/bin/php的绝对路径面板环境下 PHP 可能不在默认/usr/bin/下。坑四cron 检测脚本把活域名全部标成失效现象跑了一次检测域名池里 80% 的域名状态变成停用但手动浏览器访问这些域名都是正常的。原因检测脚本的 User-Agent 是 PHP 的默认 UAPHP-curl之类目标服务器的 WAF 把这些请求当成脚本攻击直接回了验证码或者 403。解决在 curl 请求里伪装一个真实浏览器 UA并加上随机延迟。每次检测之间的间隔不要固定成完全相同的秒数否则容易被行为分析识别。坑五后台登录后频繁掉线现象登录后台操作两分钟就被踢回登录页有时候刚登录进去点一下菜单就掉了。原因PHP session 配置的session.save_path指向的目录不可写或者cookie_domain配置和当前访问域名对不上。解决检查php.ini里session.save_path指向的目录是否存在且有写权限然后在后台配置里确认 session cookie 的作用域只限定在当前站点。如果你用 IP 访问后台cookie_domain留空即可不要写成域名。6. 上线后的验证与优化用访问日志反推跳转策略6.1 三分钟快速验证清单部署完不能直接撒手不管我习惯上线后花三分钟走一遍完整链路验证项操作预期结果后台可登录访问 admin 登录能进入域名池管理页新增域名生效后台添加一条 target_domain状态为启用权重生效跳转入口可达浏览器访问go/xxxx3 秒内落到目标域名JS 兜底生效临时停用主目标域名再访问自动落到备用域名检测脚本可跑手动执行php check_domains.php日志有输出无效域名状态翻转这套验证清单我在每次部署完都会跑一遍尤其停用目标域名之后再恢复确认状态翻转正常。6.2 用跳转日志调整权重系统跑一天后jump_log表里会积累大量记录。这时候可以根据日志做一次权重修正按目标域名聚合统计每个域名的跳转次数、失败次数和设备分布。SELECT target_domain, COUNT(*) AS total_visits, SUM(CASE WHEN is_success 1 THEN 1 ELSE 0 END) AS success_visits, ROUND(SUM(CASE WHEN is_success 1 THEN 1 ELSE 0 END) / COUNT(*) * 100, 2) AS success_rate FROM jump_log WHERE visit_time NOW() - INTERVAL 24 HOUR GROUP BY target_domain ORDER BY success_rate DESC;这段 SQL 统计 24 小时内各域名的访问量和成功率。用法说明is_success是跳转表里的一个标志字段1 表示跳转成功0 表示目标域名未响应success_rate是算出来的成功率你会发现有些域名虽然检测脚本判定是活的但真实用户访问时的成功率只有 60%——大概率是域名被区域运营商拦了而检测脚本的服务器不在那个区域。碰到这种情况把低成功率域名的权重降下来把高成功率的权重提上去。从那以后我每次上线都强制自己跑一遍这套验证流程并且每天看一眼跳转成功率这个指标。它不是摆设只要成功率开始往下走就意味着域名池里开始出现被盾的成员提前处理总比用户卡在空白页上强。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进