JSON 最佳实践完全指南

通用 阅读约 16 分钟
JSON最佳实践安全性能API 设计

JSON 最佳实践综合指南,涵盖命名规范、Schema 设计、错误处理、性能优化以及面向生产应用的安全考量。

命名规范

选择一种规范并坚持使用:

// ✅ camelCase(JavaScript 规范,最常见)
{
  "firstName": "张三",
  "lastName": "李四",
  "createdAt": "2026-07-22T10:00:00Z"
}

// ✅ snake_case(Python 规范,也很常见)
{
  "first_name": "张三",
  "last_name": "李四",
  "created_at": "2026-07-22T10:00:00Z"
}

// ❌ 避免混合规范
{
  "firstName": "张三",
  "last_name": "李四",  // 不一致!
  "createdAt": "2026-07-22T10:00:00Z"
}

建议:JavaScript/TypeScript API 使用 camelCase,Python/Ruby API 使用 snake_case。记录你的选择。

数据类型最佳实践

数字

// ✅ 数值使用数字类型
{ "price": 19.99, "quantity": 42 }

// ❌ 不要用字符串表示数字
{ "price": "19.99", "quantity": "42" }

// ✅ 大整数使用字符串(精度问题)
{ "id": "9007199254740993" }

// ✅ 缺失的数字用 null
{ "discount": null }

日期和时间

// ✅ ISO 8601 格式(推荐)
{ "createdAt": "2026-07-22T10:30:00Z" }
{ "date": "2026-07-22" }
{ "time": "10:30:00" }

// ❌ 避免歧义格式
{ "date": "07/22/2026" }  // MM/DD/YYYY 还是 DD/MM/YYYY?
{ "timestamp": 1690000000 }  // Unix 时间戳 - 可读性差

布尔值

// ✅ 使用真正的布尔值
{ "isActive": true, "isDeleted": false }

// ❌ 不要用字符串或数字
{ "isActive": "true" }
{ "isActive": 1 }

null vs 缺失

// ✅ "明确为空" 使用 null
{ "middleName": null }

// ✅ "不适用" 或 "默认值" 省略字段
{ "firstName": "张三", "lastName": "李四" }
// middleName 省略 - 不适用

// ❌ 不要用空字符串表示缺失
{ "middleName": "" }  // 这是故意为空还是缺失?

安全最佳实践

永远不要信任用户输入

// ✅ 安全解析
function safeParse(json) {
  try {
    const data = JSON.parse(json);
    // 验证 schema
    if (!validate(data)) {
      throw new Error('数据验证失败');
    }
    return data;
  } catch (e) {
    throw new Error('JSON 解析失败: ' + e.message);
  }
}

防止原型污染

// ✅ 安全解析,递归清理
function safeParse(json) {
  const data = JSON.parse(json, (key, value) => {
    if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
      return undefined;
    }
    return value;
  });
  return data;
}

大小限制

const MAX_JSON_SIZE = 1024 * 1024; // 1MB

function safeParseWithLimit(json) {
  if (Buffer.byteLength(json, 'utf8') > MAX_JSON_SIZE) {
    throw new Error('JSON 数据过大');
  }
  return JSON.parse(json);
}

性能优化

最小化载荷

// ❌ 冗长
{
  "userIdentifier": "12345",
  "userFullName": "张三",
  "userEmailAddress": "zhangsan@example.com"
}

// ✅ 简洁(配合文档)
{
  "id": "12345",
  "name": "张三",
  "email": "zhangsan@example.com"
}

大集合使用分页

// ✅ 分页响应
{
  "data": [...],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "total": 150,
    "totalPages": 8
  }
}

常见陷阱

尾随逗号

// ❌ 无效的 JSON
{ "name": "张三", "age": 30, }

// ✅ 有效的 JSON
{ "name": "张三", "age": 30 }

注释

// ❌ 无效的 JSON(使用 JSONC 或 JSON5 支持注释)
{
  // 这是注释
  "name": "张三"
}

单引号

// ❌ 无效的 JSON
{ 'name': '张三' }

// ✅ 有效的 JSON
{ "name": "张三" }

API 设计模式

统一信封格式

// ✅ 成功响应
{
  "success": true,
  "data": { ... },
  "meta": { "requestId": "abc123" }
}

// ✅ 错误响应
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "输入无效",
    "details": [...]
  }
}

相关资源

各语言 JSON API 对比

语言 序列化 反序列化 美化输出 配置方式
Python json(内置) json.dumps(obj) json.loads(str) json.dumps(obj, indent=2) ensure_ascii, default, cls
JavaScript JSON(内置) JSON.stringify(obj) JSON.parse(str) JSON.stringify(obj, null, 2) replacer, space
Java Jackson / Gson mapper.writeValueAsString(obj) mapper.readValue(str, Class.class) mapper.writerWithDefaultPrettyPrinter() 注解、Module、Feature
Go encoding/json(内置) json.Marshal(obj) json.Unmarshal(data, &obj) json.MarshalIndent(obj, "", " ") struct tag
C# System.Text.Json(内置) JsonSerializer.Serialize(obj) JsonSerializer.Deserialize<T>(str) WriteIndented = true JsonSerializerOptions
TypeScript JSON(内置) JSON.stringify(obj) JSON.parse(str) JSON.stringify(obj, null, 2) replacer, space
Rust serde_json serde_json::to_string(&obj) serde_json::from_str::<T>(str) serde_json::to_string_pretty(&obj) serde attributes, custom (de)serializers

常见问题 (FAQ)

JSON 序列化时如何处理日期时间类型?

大多数语言的 JSON 库默认不支持日期时间类型。通常做法是序列化为 ISO 8601 格式字符串(如 "2026-07-15T10:30:00Z")或 Unix 时间戳,反序列化时再转换回日期时间对象。

如何忽略 JSON 序列化中的 null 值或空字段?

不同语言的实现方式不同:Python 可在自定义编码器中过滤 None 值;JavaScript 可使用 replacer 函数;Java Jackson 用 @JsonInclude 注解;Go 使用 omitempty struct tag;C# 设置 DefaultIgnoreCondition。

JSON 序列化时如何处理循环引用?

循环引用是 JSON 序列化的常见陷阱。标准 JSON 库通常会抛出异常或栈溢出。解决方案包括:使用 @JsonIdentityInfo 注解(Java Jackson)、实现自定义序列化器、将对象图转换为 DTO 后再序列化。

为什么我的私有字段没有被序列化?

JSON 序列化库通常只序列化公开(public)字段或带有 getter 的属性。Python 的 json 模块默认只序列化 dict 的公共键;Java Jackson 可通过 @JsonInclude 注解包含非公共成员。

JSON 序列化性能有哪些优化技巧?

1) 复用序列化器实例;2) 对于大型数据,使用流式 API;3) 使用编译时生成(C# Source Generator、Go easyjson);4) 避免过多嵌套层次;5) 使用数据库分页或分块传输大 JSON。

推荐工具

以下工具可以帮助你在 通用 开发中更高效地处理 JSON 数据:

相关文章