把“有效地址集合”定义成一份可枚举的匹配规则,而不是一份地址清单:先用查询参数白名单固定哪些参数参与寻址,再对剩余参数做排序归一化,最后让自定义404错误页只对归一化后仍不匹配的请求返回404。这样做的依据是,无限增长的是参数的排列组合数量,不是有效地址的数量;只要规则有限,集合就是有限的。
条件一:参数只影响展示,不影响内容主体。此时应把这类参数全部排除在有效地址集合之外,只保留路径与少数寻址参数。典型判断证据是,同一路径加上不同排序参数、跟踪参数后,返回的正文主体、标题、主要链接集合一致,差异只出现在非主体区域。
条件二:参数会改变内容主体。此时不能一刀切排除,而应把参与寻址的参数写成白名单,并对取值做规范化,例如统一大小写、去掉首尾空白、把等价写法映射到同一规范值。只有规范化后仍落在允许集合内的组合,才视为有效地址。
选择哪一种,取决于参数是否改变主体内容,而不是取决于参数数量多少。参数多但都不改变主体,仍应排除;参数少但其中一个改变主体,就必须保留并规范化。
第一步,定义白名单与规范化函数,并把它写进服务端路由逻辑,而不是只写在页面脚本里。第二步,在自定义404错误页之前加一层归一化判断:请求先归一化,再与有效集合比对,命中则正常渲染,不命中才进入404。
这个动作的结果会直接决定下一步:如果归一化后404请求量明显下降,说明此前大量“无效地址”其实是等价写法,下一步应继续完善映射规则;如果归一化后404量几乎不变,说明增长来自真正未定义的参数组合,下一步应转向收紧白名单,而不是继续扩充映射。
需要提醒的是,请求量或抓取量归零不能单独证明处理正确。它还可能来自日志采样变化、上游缓存命中、爬虫策略调整或站点整体流量波动。要区分这些解释,应同时核对日志中归一化前后的请求样本、缓存命中记录与来源分布,而不是只看一个总量。
假设某目录页地址形如 /list?color=red&size=m&sort=price&page=2,其中只有 color、size、page 改变主体内容,sort 只改变顺序。若把 sort 纳入有效集合,则 sort 的每一种取值都会派生出一个“有效地址”,组合数随取值增多而膨胀。若把 sort 排除,并对 color、size 做小写归一化、对 page 限定为整数,则有效集合的规模由允许取值数决定,不再随排列增长。
这个假设说明的是比较方法:先固定哪些参数参与寻址,再数允许取值的笛卡尔积,而不是数实际出现过的地址。前者是定义,后者只是观测结果。
例外一:参数值本身构成内容标识,例如资源ID、版本号、语言代码。这类参数不能做模糊归一化,只能做格式校验,否则会把不同内容合并成同一地址。
例外二:参数顺序在部分实现中会影响缓存键。若归一化只改变顺序而不改变缓存键,可能出现同一内容被重复缓存。此时应在归一化的同时统一缓存键,否则自定义404错误页的命中判断与缓存行为会不一致。
例外三:robots.txt 的抓取限制不等于可靠的索引移除,站点地图也不保证收录。即使把无限参数组合挡在404之外,也不应把抓取限制当作清理已收录地址的手段;是否收录仍需按各搜索引擎的支持情况分别核查。
适用条件可以概括为:路径稳定、参数语义可分类、服务端能在渲染前完成归一化。若参数语义无法分类,或归一化只能在客户端完成,则应先缩小范围,只对可分类的参数实施白名单,其余保持原样,避免把有效地址误判为404。