7.2 错误页异常映射与线上排障


7.2 错误页异常映射与线上排障

本节摘要:错误处理是健壮性的另一半:错误页把用户与堆栈隔开,异常映射把故障按状态码与类型分流,结构化日志把线上事故还原成完整故事链。上一站封住了攻击者从正门进来的路,本站堵住异常从侧门泄密的路,并交付一套线上排障的固定动作——上线之后,你会经常用到它们。

404背后的异常去哪了

错误路由有两级配置,粒度从细到粗。页面级在页面指令上声明,本页出错就跳指定页面;全局级在部署描述文件里集中映射,按状态码与异常类型分流全站:

<error-page> <error-code>404</error-code> <location>/errors/not-found.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/errors/server-error.jsp</location> </error-page> <error-page> <exception-type>java.sql.SQLException</exception-type> <location>/errors/db-error.jsp</location> </error-page>

维护期的建议很明确:全局映射为主。几十个页面各自声明页面级错误页,是配置碎片化的典型——改一次错误页风格要动几十个文件。全局一份配置管全站,页面级只留给确实需要特殊去处个例。

被映射到的错误页要声明自己特殊的身份,才能拿到异常对象:

<%@ page isErrorPage="true" %> <%-- exception 隐式对象在此可用:记住它,别展示它 --%> <p>服务开小差了,请稍后重试。</p>

注意最后一行的克制:错误页拿到异常是让你记录,不是让你展示。完整的错误分流与信息出口画成图如下。

图7-2 错误分流与信息出口

图7-2 错误分流与信息出口

给用户看体面,给运维看全貌

错误信息有三个观众,三种出口。用户该看到体面的提示页:一句人话、一个重试入口,绝无堆栈、路径、查询语句。日志该看到全貌:异常类型、堆栈、请求地址、会话线索、发生时间——排障的原料全在这。攻击者什么都别想看到:容器默认错误页会把堆栈原样打印,堆栈里的类名、包名、行号拼起来就是半张系统地图,这是 7.1 节攻击面清单上必须封掉的出口之一。

日志记录遵循最小必要原则:记异常码与参数占位,不记完整语句与真实参数值;记用户标识与会话线索,不记密码与证件号。查得到问题、带不出敏感数据,两个要求满足齐了才算合格。另外把日志写成结构化一行一条的习惯,后续接日志分析平台时无需二次加工——今天多打的一个字段,就是三个月后深夜排障时少翻的一小时。

案例:一次深夜 500 的标准排障

背景:上线后的第一个加班夜,值班群报障:订单列表页偶发 500,刷新两三次又能恢复,频率约百分之一。用户看到的是体面错误页(错误页体系生效了),但没人知道背后是什么错。

操作:按固定动作链走四步。第一步看状态码与时间点,从访问日志捞出所有 500 记录,确认集中在订单列表接口。第二步找异常栈——应用日志按请求地址过滤,捞到反复出现的同一栈顶:连接获取超时。第三步还原上下文,结合连接池监控,发现晚高峰连接归还存在泄漏(某条早退路径没走到归还逻辑,正是 4.3 节警告过的病灶)。第四步定位代码,在服务层找到那条提前返回的路径。

结果:补上自动归还的写法,上线后同类 500 归零。

解读:复盘这次排障,四步动作链——对时间、捞栈顶、还原上下文、回代码——每一步的原料都来自本节铺好的基础设施:错误分流让故障可计数,结构化日志让栈可检索,监控让上下文可还原。排障速度从来不取决于排障者多聪明,而取决于这些基础设施铺得有多全。

变式:偶发又不可复现的故障,如果日志没抓到现场,下一招是加观察点再等复发:在嫌疑路径的入口出口各加一行计时与状态日志,成本极低,复发时现场自动齐全。千万别上生产环境开调试断点或远程调试——那是把线上当开发机,风险完全不成比例。

💡 关键直觉:错误处理的完整闭环是"用户侧体面、日志侧完整、攻击面封闭"三位一体。三者缺一,错误就不再是故障信号,而变成故障本身——泄密、丢线索、或者让用户替系统买单。

异常翻译:把技术异常变成业务语言

排障链之外,还有一套"异常翻译"的纪律值得单独交代。数据层抛出的异常是技术语言——连接超时、唯一键冲突、字段截断;用户与控制器需要的是业务语言——库存不足、单号重复、信息超长。翻译的动作发生在服务层:技术异常在数据访问层向上抛,服务层捕获后翻成带业务语义的自定义异常再往上抛,控制器按业务异常选视图。没有这层翻译的站点,错误页只能千篇一律地说"系统繁忙",排障也得从一坨技术栈里反推业务语义。青梧书肆的整改动作是把高频的六七种数据异常逐个配上业务翻译,顺带在翻译点补了日志埋点——同一处代码,向上给用户体面、向下给运维线索,一举两得。判断一个站点翻译层是否健全有个快捷办法:看错误日志里技术异常直接冲到控制器层的比例,比例越高,翻译层欠账越多。

日志级别的使用纪律

排障原料的质量取决于日志级别用得对不对。ERROR 留给"需要人介入的故障":异常导致请求失败、资损风险、数据不一致——ERROR 一响,值班必须看。WARN 留给"自动恢复但值得留意":重试成功、降级触发、慢查询超阈值——WARN 是趋势信号,攒多了就是事故前兆。INFO 留给"业务里程碑":订单创建、支付完成、部署动作——INFO 是业务审计线,出事时用来还原"当时发生了什么"。DEBUG 默认关,只在定向排查时对特定包临时打开。老站最常见的病是级别通胀:把一切记成 ERROR,狼来了三次之后,真狼来了也没人看。青梧书肆的日志整改花了半天把存量日志重新定级,顺带定下规矩:新日志提PR时必须声明级别理由。定级准确的日志系统,值班体验完全是另一个世界——该吵的闹钟才会被当真。

本节要点回顾

  • 全局映射为主:状态码与异常类型两级分流集中在部署描述文件,页面级声明只留给特例;
  • 错误页要极简:拿到异常对象是为了记录,绝不是为了展示;错误页自身抛异常会跌回默认页;
  • 三个观众三种出口:用户看体面提示、日志记全貌、默认堆栈页必须被映射覆盖;
  • 最小必要原则:日志查得到问题、带不出敏感数据,结构化格式为分析平台预留接口;
  • 四步排障链:对时间、捞栈顶、还原上下文、回代码,速度取决于基础设施的完备度。

安全补课到此结业:攻击面封住、错误出口管住。下一章做性能体检与工程规范——站点还得扛得住流量、经得起下一任维护者检验。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U