答案取决于一个前提:这个功能开关是否会改变页面返回的 HTTP 状态码或响应体内容。如果会,扫描结果本身就是版本相关的证据,必须把开关状态和扫描批次绑定记录;如果只改变前端渲染、状态码和响应体完全一致,那么扫描工具看到的版本不会变化,记录重点应放在渲染层快照上。判断错了,后续的对比和回退都会建立在错误基线上。
功能开关(feature flag)在实现上可能落在几个不同位置,每个位置对死链扫描工具的意义完全不同。
选择依据很直接:用 curl -I 或等价方式在开关开、关两种状态下取同一路径的响应头和响应体摘要。如果状态码或正文哈希不同,就按“会改变扫描结果”处理;如果完全一致,就按“不改变扫描结果”处理。这个动作只需要几分钟,但它决定后面所有记录工作的方向。
此时扫描结果是有版本属性的,不能只留一份最新结果。需要做到三件事。
第一,把开关状态作为扫描批次的元数据固定下来。记录内容至少包括:开关名称、当前取值、扫描开始与结束时间、扫描工具版本、被扫描的路径范围。这样两份扫描报告之间才有可比性。
第二,两次扫描之间只允许一个变量变化。假设你在开关关闭时扫了一次,开启后又扫一次,中间还改了路由规则,那么两次结果的差异就无法归因到开关上。要得到可用的证据,就得保证开关是唯一变动项。
第三,保留原始输出而不是只看汇总数字。汇总里的“死链数从 12 变成 5”不能说明是哪几条消失了、是修复了还是被开关屏蔽了。原始列表才能回答这个问题,也才能让下一步判断成立。
一个注明假设的短例子:某路径在开关关闭时返回 200 且正文含 3 个指向旧域名的链接,开启后返回 200 但正文只含 1 个。假设这两次扫描之间没有其他改动,那么差异可以归因到开关;此时如果旧域名已失效,死链数下降并不代表问题被修复,只代表问题被隐藏。下一步动作应该是检查开关关闭状态下的那 3 条链接是否仍需要处理,而不是直接宣布修复完成。
这种情况下,死链扫描工具在两种开关状态下得到的结果应当一致。如果确实一致,扫描层面不需要记录版本,因为扫描看到的对象没有变化。但这不等于什么都不用记。
真正会变的是用户和爬虫实际渲染后看到的链接。此时记录重点转向渲染层:在开关开、关两种状态下分别保存渲染后的 DOM 快照或链接清单,并标注抓取时间。判断依据是渲染后链接集合是否存在差异——有差异就记录,无差异就可以跳过。
这里有一个容易踩的坑:扫描结果一致,容易被误读为“开关没有影响”。合理的解释至少有两种,一是开关确实只影响渲染层,二是扫描工具本身不执行脚本、根本没看到渲染层。要区分这两者,需要单独确认扫描工具是否具备渲染能力,而不是从结果一致倒推结论。
记录位置要跟着变更流程走,而不是另建一套。可行的做法是把开关状态写进变更单或发布记录,与代码版本、配置版本放在一起;扫描报告按批次归档,批次标识与变更单关联。这样回退时能直接找到“开关处于某状态时”的那份扫描结果。
实施动作与结果的关系可以这样看:如果你把开关状态写进了变更单,那么回退时就能定位到对应批次的扫描结果,判断回退后是否恢复到预期状态;如果没有写,回退后只能重新扫描一次,而重新扫描得到的是当前状态,无法证明它等于变更前的状态。
以下情况可以不记录版本:开关只影响样式、文案或非链接元素,且已确认两种状态下链接集合完全相同。此时记录的价值低于维护成本。但一旦开关涉及路由、重定向或链接生成逻辑,就回到条件一的处理方式。
有些变化不能只靠扫描结果解释。比如开关关闭时路径返回 403,开启时返回 200,扫描工具可能把 403 记为异常,但这属于访问控制而非死链。再比如开关控制的是重定向目标,扫描工具跟随跳转后拿到 200,看起来正常,但跳转链本身可能已经指向不该去的位置。这类情况需要单独核查响应头中的跳转序列,而不是只看最终状态码。
另外,robots.txt 里的抓取限制不等于可靠的索引移除,站点地图也不保证收录。如果开关同时改动了这两类文件,扫描结果的变化和索引状态的变化是两件事,不能用前者推断后者。不同搜索引擎对这些信号的支持情况需要分别核查,不能互相替代。
把开关状态和扫描批次绑定记录,是为了让每一次对比都有明确基线;基线不清,后面的修复和回退判断都会失去依据。