NaN 和 Infinity 能放进 JSON 吗
结论:JSON 只有十进制数字字面量,没有 NaN、Infinity、-Infinity。JSON.stringify 会静默把它们变成 null,接口里因此出现过大量「明明是数字却收到 null」的故障。

结论:不能。JSON 只允许十进制数字字面量,JSON.stringify 会把 NaN 和 Infinity 静默序列化成 null;要表达这类状态,用 null 加一个说明原因的状态字段,或使用带明确约定的字符串。
JSON.stringify({ ratio: NaN, limit: Infinity });
// '{"ratio":null,"limit":null}'
没有任何报错,也没有任何警告,两个值直接变成了 null。这是最容易在生产环境里埋雷的一类转换。
标准里为什么没有
RFC 8259 的数字语法是:
number = [ minus ] int [ frac ] [ exp ]
只认十进制字面量。NaN、Infinity 是 IEEE 754 的特殊值,不是数字字面量;把它们写进 JSON 文本,解析器会当成非法标识符。
JSON 的设计目标之一是跨语言可解析,而这些特殊值在不同语言里的表示、比较语义都不一致,干脆排除在外。
各语言的实际行为
| 语言 | 行为 |
|---|---|
JavaScript JSON.stringify |
静默转成 null |
Python json.dumps |
默认输出 NaN(非标准),allow_nan=False 时抛 ValueError |
Go encoding/json |
序列化时报错 unsupported value: NaN |
| Java Jackson | 默认输出 "NaN" 字符串,可配置为抛错 |
同一个值,四种行为。跨语言接口出现「数字字段偶尔是 null」时,先怀疑这一层。
该用什么表达
方案一:字符串约定。 用 "NaN"、"Infinity" 加类型说明,消费方显式判断。缺点是把类型判断推给了每个调用方。
方案二:null + 状态字段。 更推荐的做法:值不可用时给 null,另加一个字段说明原因,例如 {"avgLatency": null, "avgLatencyStatus": "no-sample"}。语义清楚,也便于统计。
方案三:换个单位。 很多「除零得到 Infinity」的场景,本质是没有样本。直接返回 null 并让前端显示「暂无数据」,比传一个无穷大更接近业务事实。
方案四:整数化。 如果是精度问题导致的 NaN(比如 0/0、Infinity - Infinity),在计算前就做防御,别让脏值流到序列化这一步。
顺手检查
- 前端把
JSON.parse结果直接喂给图表库,null会让折线断开——要确认这是预期行为 JSON.stringify还会丢掉undefined、函数、Symbol,对象的这些键会整个消失,不是变成null- 后端用 Python 的
json.dumps且allow_nan为默认True,产出的就不是标准 JSON,浏览器JSON.parse会失败
常见问题
遇到「数字字段收到 null」应该怎么排查?
先确认该字段在序列化前是不是 NaN 或 Infinity。JavaScript 的 JSON.stringify 会把这两种特殊浮点静默转成 null,Go 会直接报错,Python 默认则输出非标准的 NaN。
是否可以用字符串 "NaN" 表示特殊值?
可以,但要配上明确的类型约定,让每个消费方显式判断。更稳妥的做法是值不可用时给 null,另加一个状态字段说明原因。
相关工具
- JSON 格式化与校验:看到
null时先确认原始值是不是特殊浮点 - JSON 与 YAML、XML 的互转边界:YAML 支持
.nan、.inf,互转时要额外处理