唯一责任方应当定义为“最终把 URL 写进可抓取 HTML 的那套系统”,而不是最先产生路径片段的系统。CMS、商品中心、路由网关、CDN 重写和前端框架都可能参与拼 URL,但只有最终渲染结果能决定爬虫看到什么。若无法确定谁最后写入,就先做一次输出归属标记,再决定由谁对死链负责。
多个系统同时生成网址时,常见现象是路径由 A 系统拼接、参数由 B 系统追加、前缀由 C 系统重写。此时若把责任交给“配置了规则的系统”,往往找不到人,因为每个系统都只负责一段。
更可执行的做法是按发布链路分层:
唯一责任方应落在发布层。理由是死链检查面对的是“爬虫请求到的 URL”,不是内部数据库里的路径。发布层是最后一个能把错误 URL 拦住的位置,也是修改后能直接改变抓取结果的位置。
如果页面链接、分页、面包屑和站点地图都由服务端模板统一渲染,那么责任方就是模板与路由配置的维护方。此时生成层可以继续产生片段,但组装和发布必须收口到同一处。
实施动作:在模板输出 URL 的位置加一个统一函数,例如 buildUrl(pathParts),禁止模板直接拼接字符串。这个动作的结果是,任何新增参数、语言前缀或尾斜杠变化都只改一处。下一步做死链检查时,若发现同一路径在不同页面表现不一致,就能直接判断是调用方绕过了统一函数,而不是继续追多个上游系统。
如果链接由前端框架在浏览器中生成,而站点地图和预渲染由另一套任务产出,责任方应定义为“预渲染或服务端输出任务”,而不是浏览器端组件。因为爬虫能否稳定看到链接,取决于预渲染结果,不取决于用户浏览器里最终点开什么。
实施动作:把前端路由表导出为一份只读清单,交给预渲染任务和站点地图任务共同读取。这个动作的结果是,前端改路由时不会只改浏览器端,而会同步影响预渲染输出。下一步若死链检查发现站点地图里有旧路径,就可以先查这份清单的版本,而不是先怀疑 CDN 缓存。
当组织内无法靠流程约定确定责任方时,可以用一次性的输出归属标记来定位。方法是在每个系统生成的 URL 上附加一个不影响访问的调试参数或注释,例如在预发布环境输出 ?src=assembler、?src=template。注意这只能用于预发布,不能长期留在线上可索引页面。
假设一个短例子:某分类页 URL 在站点地图里是 /c/100,在页面分页里是 /c/100/,在跳转规则里又变成 /category/100。若预发布输出显示站点地图来自发布任务、分页来自模板、跳转来自网关,那么责任方应定为发布任务,因为它输出的 URL 被直接提交给爬虫。网关只负责请求到达后的处理,不能替发布层决定对外暴露哪个 URL。
这个判断的下一步是:先修发布任务的 URL 生成,再观察死链检查中该路径的请求是否集中到新形式。若仍有旧形式请求,还要区分是外部历史链接、缓存页面还是跳转规则仍在引用,不能仅凭请求量下降就认定处理完成。
传输层通常不是唯一责任方,但有两种例外。第一,重写规则把已发布 URL 改写成另一个对外可见 URL,且页面 HTML 无法感知。第二,跳转服务对旧路径返回 301 或 302,而发布层已经不再输出该路径。此时传输层要对“请求最终落到哪里”负责,但仍不改变发布层对“页面里写什么 URL”的责任。
另一个例外是 robots.txt 和站点地图的边界。robots.txt 的抓取限制不等于可靠的索引移除;站点地图不保证收录。即使发布层把 URL 写对了,也不能把收录结果当成责任归属的证据。HTTPS 同样不保证安全无漏洞或排名。不同搜索引擎对参数、尾斜杠和重写的支持情况须分别核查,不能用一个平台的表现推断另一个平台。
实际操作时,可以按以下顺序判定,避免多系统互相推诿:
这样做的结果是,每次死链检查都能落到一个可修改的位置。若某个 URL 同时出现在多个来源,优先修发布层,再处理传输层引用。若发布层已修正但旧 URL 仍有请求,应继续区分历史外链、缓存和跳转规则,而不是把请求归零当作唯一正确证据。最终,唯一责任方不是“谁最早生成”,而是“谁最后把 URL 交给爬虫”。