message Coupon {
  optional int32 discount = 3;
}
// 生成代码后:coupon.hasDiscount() 才能区分未设置与 0

优惠券的 discount 字段传 0 表示免减,运营后台看到的是「未设置」,接口直接把券判成无效。抓包发现报文里根本没有第 3 个字段,hasDiscount() 返回 false。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。

原因不复杂,proto3 的标量字段用默认值表示「没有」,0、空串、false 都不会写进报文。接收端无法区分调用方显式传了 0 还是压根没填,业务语义在这一层就丢了。

「Proto3 零值序列化」确认了原因之后,改动尽量只碰那一处,顺手改的东西后面最容易出问题。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

处理上按这个顺序:需要区分时把字段声明成 optional 生成代码里才有 has 方法;或者用 google.protobuf.Int32Value 包一层 未设置时是 null;老数据兼容阶段让调用方改用 -1 表示未设置 服务端统一转换;改完用 protoc --decode 看报文里字段是否真的出现。

改完只确认一件事:传 0 的请求报文里能看到第 3 个字段 hasDiscount() 返回 true 后台不再显示未设置。

作者 9823189