从一次Java“防守失位”看代码评审:这个案例如何评价这次防守失位?
目录导读
- 引言:一次不起眼的“失位”
- 案例还原:代码里的“防守漏洞”是什么?
- 深度剖析:为什么说这是“防守失位”而非“技术不足”?
- 评价框架:从四个维度看这次失位
- 实战问答:常见争议与解决思路
- 防守不是堆砌代码,而是设计意识
引言:一次不起眼的“失位”
在代码评审中,我们经常听到“这里防守做得不够”或者“这个边界没考虑到”,但什么是真正的“防守失位”?我们通过一个Java后端接口案例,来还原一次典型的“防守失位”,并探讨如何客观评价它。

这个案例来自一个用户订单查询接口,需求很简单:根据用户ID和订单状态,返回订单列表,初看代码,逻辑清晰、命名规范,甚至通过了单元测试,但评审专家却指出了“严重防守失位”,为什么?
案例还原:代码里的“防守漏洞”是什么?
public List<Order> getOrdersByStatus(Long userId, Integer status) {
if (userId == null) {
throw new IllegalArgumentException("userId不能为空");
}
// 注意:没有校验status是否合法
return orderMapper.selectByUserIdAndStatus(userId, status);
}
看似正常,但失位在哪里?
- 失位点1:status参数未校验,如果前端传入
status=99(未知状态),SQL会正常执行,但返回空列表,前端展示无差别空状态,如果业务上“空状态”和“无权限”需要区分,这就是逻辑漏洞。 - 失位点2:分页参数缺失,如果该接口被恶意或误用调用,例如一次查询百万级订单,数据库压力骤增,这就是性能防守失位。
- 失位点3:异常类型过粗,直接抛
IllegalArgumentException,上层如果是统一异常处理器还好,但如果没有,则返回500错误,把“参数错误”误报为“服务器错误”。
深度剖析:为什么说这是“防守失位”而非“技术不足”?
“技术不足”是不会写代码,而“防守失位”是知道该做什么,但在关键点上选择了“轻描淡写”。
在这个案例中,开发者的防守意识体现在“校验userId非空”上,说明他有校验意识,但为什么唯独漏了status和分页?常见原因有三:
- 惯性思维:认为“状态码是枚举,数据库里只有那几个值”,但代码没有体现这种约束。
- 过度信任上游:觉得“前端已经下拉框限定了”,但Java后端必须做到“永不信任输入”。
- 测试盲区:单元测试只测了正常路径,没有测边界值、非法值、大数量级。
这次“失位”本质上是防守的覆盖度不均衡——守住了最容易想到的点,漏掉了最容易出大问题的点。
评价框架:从四个维度看这次失位
我们用一个“四维评价法”来打分(满分10分):
| 维度 | 案例表现 | 得分 |
|---|---|---|
| 参数完整性 | 校验了userId,漏了status、分页参数 | 6 |
| 异常处理策略 | 抛异常但未定义业务码,可能误报500 | 5 |
| 性能与资源防守 | 无分页、无最大返回条数限制 | 3 |
| 可测试性与可维护性 | 测试覆盖正常路,未覆盖非法值 | 5 |
综合评价: 这不是一个“烂代码”,而是一个基本功不扎实、防守不均匀的典型案例,它反映了开发者“有防守意识,但缺少系统化防守清单”。
实战问答:常见争议与解决思路
Q1:如果前端已经做了枚举限制,后端还要校验吗?
A:必须校验,前端校验是用户体验,后端校验是安全保障,任何客户端请求都可以被伪造,所以后端必须对所有输入参数做白名单校验。
Q2:分页参数是否一定要强制?
A:不一定强制,但必须有“最大数量”防线,如果未传分页,默认返回20条,且上限为100条,这属于“隐性防守”,防止运维事故。
Q3:抛IllegalArgumentException和自定义异常有什么区别?
A:前者是JDK基础异常,如果全局异常处理器不拦截,会返回500,自定义业务异常(如InvalidStatusException)可携带明确的错误码和消息,返回400或422,前端才能友好提示。
Q4:如何避免下次再“失位”?
A:建立“参数校验清单模板”,必填性、类型、取值范围、长度、上限、格式、业务关联校验,每次写接口时按清单逐项打勾。
防守不是堆砌代码,而是设计意识
这个Java案例给我们的核心教训是:防守失位不是“少写了几行if”,而是“防守思维没有体系化”。
评价一次防守失位,不能只看“这次出了什么事”,而要问:“这个系统的防守机制是点状的,还是面状的?”点是偶然,面是能力。
下一次当你写完一个接口,不妨多问自己三句话:
- 如果我没写这段校验,谁会遭殃?
- 如果数据量翻10倍,我的代码还能撑住吗?
- 如果上游是个恶意用户,他能利用我这个接口做什么?
这三句话,就是最好的防守清单起点。
(全文完)