灰度阶段只覆盖少量路径和少量访问者时,404页面设置看起来正常,并不代表全量发布后仍然成立。真正会暴露例外的,往往是那些在样本里没出现、但全量后必然出现的请求类型:带查询参数的旧链接、大小写变体、尾斜杠差异、多级目录、被外部引用的静态资源,以及需要返回410而非404的已删除内容。灰度能验证的是“配置在样本上生效”,不能验证“规则覆盖所有真实流量”。
灰度通常按流量比例或路径前缀切分,这决定了它的样本结构。假设你只对/blog/下的一部分文章开启新404页面,那么灰度里出现的几乎都是文章详情页的缺失请求。全量后才会涌入分类页、标签页、分页、附件页、作者页,以及从旧域名迁移过来的带参数链接。这些请求的响应路径可能完全不同。
更关键的是,灰度往往由内部访问或少量真实用户触发,缺少外部爬虫和聚合页带来的长尾请求。于是灰度里404页面返回正常、状态码正确,全量后却出现两类例外:一类返回了200(软404),一类返回了错误的跳转目标。灰度没暴露它们,不是因为配置没问题,而是因为触发条件没被采样到。
发现例外后,常见反应是立刻改规则、加跳转或直接关掉新配置。这三种动作各有前提,不能默认通用。
?utm_参数、或尾斜杠变体)时,改写规则比逐个加跳转更稳。前提是你能用一条规则覆盖整类,而不是给每个URL单独开例外。这里没有“永远正确的选项”。灰度暴露的例外如果指向配置逻辑本身有缺陷,改写优先;如果指向样本不足,补采样比改规则更值得先做。
假设某站点把已删除的旧产品页统一设为404,并在灰度中只测试了20个已知旧链接,全部返回404页面且状态码正确。全量发布后,监控发现部分旧链接返回了200,页面内容是“未找到”的提示文本。
动作:抽取返回200的样本,检查它们是否命中了某个重写规则或默认路由。结果如果显示这些URL落入了内容管理系统的兜底模板,那么问题不在404页面本身,而在路由优先级。下一步就不是改404文案,而是调整路由顺序,让缺失路径先进入404处理。
这个假设说明:灰度验证的是“被测试的URL返回了什么”,全量暴露的是“没被测试的URL走了哪条路径”。两者的证据层级不同,不能互相替代。
要让灰度更接近全量,不是简单提高流量比例,而是补上样本结构。可以从访问日志或站点地图中抽取几类容易被忽略的请求:
补采样后,如果某类请求在灰度中稳定返回预期状态码,才可以把该类纳入“可全量”的判断。否则,全量发布仍然是在赌例外不会出现。
灰度里最容易让人放心的信号是“状态码是404”。但状态码正确只说明服务器表达了“未找到”,不说明这个表达是否适合该URL的实际情况。一个已永久删除且有替代内容的页面,返回404可能不如返回410或301;一个只是参数变体的URL,返回404可能制造大量重复缺失信号。
robots.txt的抓取限制不等于可靠的索引移除,站点地图不保证收录,这些约束同样适用于404场景:你不能用一份“不抓取”规则替代对缺失页面的正确处理。不同搜索引擎对410、软404和跳转的处理方式需要分别核查,灰度阶段如果只测了一个引擎的响应,全量后另一个引擎的表现可能不同。
因此,灰度暴露例外之后,判断顺序应是:先确认例外属于哪类请求,再确认该类请求应该返回什么,最后才决定保留、改写还是退出。跳过前两步直接改404页面,通常只是把例外从一个位置挪到另一个位置。