唯一责任方应当落在“最终输出规范化网址的那一层”,而不是生成 URL 的每一层。也就是说,多个系统都可以提出候选网址,但只能有一个系统拥有最后改写、归一和对外发布的权力;其他系统只能提交输入,不能直接决定线上 URL。判断方法不是看谁代码里出现了域名拼接,而是看谁的结果真正进入响应头、页面链接和站点地图。如果三者指向不同系统,就先确定哪一个环节能同时改变这三处输出,那个环节才是责任方。
多个系统生成网址通常有两种结构。第一种是上游系统生成内容 ID 或路径片段,下游发布系统负责拼接域名、协议、目录和尾斜杠。第二种是上游系统直接生成完整 URL,下游只做透传。两种条件下,责任方完全不同。
第一种条件下,发布系统应当承担唯一责任。上游只提供稳定标识,比如内容 ID、栏目代码或 slug,不提供域名和协议。发布系统统一决定 https、主机名、路径大小写、尾斜杠、参数保留规则。这样做的直接结果是:即使上游换了实现语言或部署环境,线上 URL 也不会跟着变化。
第二种条件下,如果上游已经生成完整 URL,就必须把上游视为责任方,或者强制收回其拼接权。否则下游只能做补救,无法阻止新 URL 继续产生。一个可执行的动作是:要求上游只输出相对路径,由发布层补全域名。如果上游拒绝改造,就应把发布层改为拒绝透传绝对 URL,并在构建阶段报错。这个报错会阻断错误 URL 进入线上,下一步才轮到修复上游模板,而不是继续在下游加正则。
判断依据可以核对三处证据:HTTP 响应中的最终地址、页面内链的 href、站点地图中的 loc。若这三处不一致,且只有发布系统能同时改变它们,责任方就是发布系统;若上游生成的绝对 URL 被原样写入这三处,责任方就是上游。这里要注意,站点地图不保证收录,它只是观察输出一致性的证据之一,不能反过来证明某个系统正确。
与直觉相反的结果经常是:日志里看到大量旧域名或带参数 URL,团队第一反应是去改生成器,但真正的问题在发布层。要区分两种解释,可以按下面顺序取证。
/A 和 /a 两个版本,且只有发布层能做重定向,责任方仍是发布层;若上游直接生成了两个绝对 URL,责任方在上游。这些证据只能说明输出差异,不能单独证明某个系统处理正确。请求量或抓取量归零也有多种解释,比如发布延迟、网络分区、抓取预算转移或 robots.txt 限制,不能仅凭归零就断定责任方已经修好。robots.txt 的抓取限制也不等于可靠的索引移除;它只影响抓取,不保证已收录地址会按预期消失。HTTPS 同样不保证安全无漏洞或排名,它只是协议层的一个条件。
把责任写成可执行约束,而不是口头约定。一个最小做法是建立“发布层唯一拼接”规则:上游只允许输出相对路径或内容标识,发布层负责补全协议、主机名和路径规范。实施后,构建阶段应能拒绝任何包含绝对域名的上游字段。这个动作的结果是:新产生的 URL 只能来自发布层,冲突面从多个系统收敛到一个系统,下一步排查才有唯一入口。
如果业务上必须保留上游生成完整 URL 的能力,例如多站点分发,那么唯一责任方应改为“分发清单的维护方”,并要求所有系统从同一份清单读取域名和路径规则。此时要额外核对不同搜索引擎的支持情况,因为 canonical、重定向和站点地图的处理并不完全一致,不能假设一个搜索引擎接受就等于全部接受。
例外情况也要写清楚:当上游系统同时承担发布职责,比如静态站点生成器既生成又输出文件,它本身就是责任方,不需要再拆出下游发布层。当多个系统并行写入同一 CDN 或对象存储时,唯一责任方应落在写入前的合并环节;如果没有合并环节,就应先建立合并环节,而不是在多个写入方之间投票。
假设一个内容平台有 A、B 两个系统。A 生成文章路径,B 生成栏目路径,两者都拼接完整域名。线上同时出现带尾斜杠和不带尾斜杠的版本。此时若只修改 B 的模板,A 仍会继续产生另一套 URL,问题不会收敛。
若改为 A、B 都只输出相对路径,由发布系统统一补全域名并决定尾斜杠,那么新 URL 只有一个来源。接下来核对响应头、内链和站点地图三处是否一致;若仍不一致,就只查发布系统,不再同时查两个上游。这个假设示例说明的是比较方法:先收敛生成权,再用三处输出验证,而不是先承诺收录或排名结果。
最终判断标准可以压成一句话:谁有权改写最终对外 URL,谁就是唯一责任方。其他系统只能提供输入,不能拥有最终发布权。责任方确定后,下一步动作才是针对该层做最小修复试验,并用响应头、内链和站点地图三处证据复查。