PATCH /v1/users/42
{"nickname": null}
{"phone": "13800000000"}

前端把昵称清空,PATCH 请求体传 {"nickname": null},后端把字段改成了空字符串。另一个页面只传 {"phone": "138..."},昵称却被重置成了默认值。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,null 和字段缺失在 JSON 里是两回事,反序列化到对象后都变成 null,代码分不清用户是想清空还是没传。更新逻辑又用了全量覆盖,没传的字段一起被写成 null 或默认值。

这次卡住的地方就在「PATCH null 语义」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

处理上按这个顺序:用 JsonNullable 或 Optional 包装字段 区分未传和显式 null;更新语句只 set 请求里出现过的字段;把清空动作改成显式的空字符串或单独接口 不要用 null 表达;给两种请求各写一条用例 断言未传字段保持不变。

改完只确认一件事:只传 phone 的请求执行后昵称保持不变 传 null 的请求昵称被清空。

作者 9823189