先固定一个判断:如果同一路径去掉查询参数能返回200,带上某组参数却返回404,问题通常不在页面本身,而在参数进入应用后的匹配、路由或数据查询环节。缩小复现条件的目标,是找到“哪一类参数值开始触发404”,而不是继续扩大抓取范围。
两种解释会产生外观相同的404,但证据不同。第一种是应用或服务器在解析参数前就拒绝请求,例如参数名不符合路由规则、参数编码被中间层改写、参数数量超出预期。第二种是参数被正常接收,但用这些值查不到对应内容,于是应用主动返回404。
区分它们最直接的动作,是构造一组最小参数并观察响应头与响应体。假设一个商品筛选页在?cat=1&page=2时正常,在?cat=1&page=2&sort=price时返回404。去掉sort恢复200,说明问题与sort参数相关;保留sort但把值换成空字符串仍返回404,则更接近参数被处理成空结果,而不是路由直接拒绝。
如果响应头里出现了应用层设置的缓存控制或自定义标记,而响应体是应用自己的404模板,通常偏第二种解释。如果响应来自网关、负载均衡或服务器默认错误页,响应体不含应用模板特征,则偏第一种解释。这个判断会决定下一步:前者查数据匹配,后者查参数解析和转发链路。
当异常只出现在特定参数上,逐条提交URL效率很低。更有效的做法是把参数拆成可比较的维度,每次只改变一个维度:参数名、参数值类型、参数个数、参数顺序、编码方式、是否与其他参数组合。
sort换成order,若404消失,说明问题在参数名映射,而非值本身。price换成纯数字、带小数点、带负号,观察哪一类先失败。若只有负号失败,问题可能在取值校验或查询条件。%20与+分别测试,若只有一种失败,问题在解码环节。每轮只改一个维度,并记录返回状态、响应体特征和响应头。这样得到的不是“某个URL坏了”,而是“哪一类参数条件会触发404”。下一步就能把范围压到具体代码路径或配置项。
部分页面正常、特定参数异常,常见原因是请求在到达应用前被中间层改写。CDN、反向代理、WAF、重写规则都可能丢弃、合并或重新编码查询参数。它们不一定返回自己的错误页,也可能把改写后的请求交给应用,由应用返回404。
可用的证据是比较同一参数在不同入口下的表现。假设直接访问源站IP带参数返回200,经过代理域名带同样参数返回404,那么差异更可能出在代理层,而不是应用代码。反过来,如果两者都404,则应优先查应用内部。
另一个动作是查看访问日志中实际到达应用的查询字符串。如果日志里参数已经丢失或变形,说明改写发生在日志记录之前;如果日志里参数完整但应用仍返回404,则问题在应用处理阶段。这个结果直接影响下一步:前者要改代理或重写规则,后者要查路由和数据查询。
旧内容或旧系统退出时,常见做法是把整组页面直接返回404。但如果其中部分参数组合仍有访问价值,粗暴处理会同时损失可用路径。更稳妥的方式是先按参数维度区分:哪些参数组合对应真实内容,哪些只是无效筛选。
假设一个旧筛选系统只保留cat和page,而sort、brand已经下线。对仍有效的cat组合返回200,对已下线的参数返回404,并确保404页面不返回200状态。这里的关键不是让所有参数都可用,而是让无效参数明确失败,同时不把有效参数一起拖入404。
如果希望旧参数引导到新路径,应使用301或302,而不是用404页面承载跳转内容。404状态码表示资源不存在,用它做软跳转会让后续判断更困难。这个动作的结果是:有效参数保持可访问,无效参数可被识别,后续清理范围也更清楚。
把候选条件压缩到最小后,做一次可复查的实验:固定路径,只保留一个可疑参数,分别测试正常值、边界值、空值和缺失值,记录每次的状态码与响应体特征。假设结果是:正常值200,空值404,缺失值200。那么可以判断应用对空参数有特殊处理,而不是整个参数不可用。下一步应查空值校验逻辑,而不是重写路由。
如果实验结果是正常值、空值、缺失值全部404,而去掉参数后200,则问题更可能在参数解析或路由匹配,应优先检查参数名映射和中间层改写。这个实验不需要覆盖全站,只需要覆盖能区分解释的那几个条件。
最后,404状态码本身只说明该请求没有对应资源。它不能单独证明参数处理正确,也不能证明某个页面应该被移除。把复现条件缩小到具体参数维度后,才能决定是修数据、修路由、修代理,还是让旧参数正式退出。