⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

7.1.2 JSON 数据格式

一句话破题

JSON 是前后端交流的"普通话"——浏览器认识它,服务器认识它,几乎所有编程语言都能读写它。

JSON 基础

json
{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com",
  "age": 25,
  "isActive": true,
  "tags": ["developer", "designer"],
  "profile": {
    "avatar": "avatar.png",
    "bio": "Hello world"
  },
  "createdAt": "2024-01-15T10:30:00Z"
}

支持的数据类型

类型示例注意事项
字符串"hello"必须用双引号
数字123, 3.14不支持 NaN、Infinity
布尔true, false小写
nullnull表示空值
数组[1, 2, 3]有序列表
对象{"key": "value"}键值对

不支持的类型

typescript
// ❌ 这些类型 JSON 不支持
const data = {
  date: new Date(),      // Date 对象
  fn: () => {},          // 函数
  undef: undefined,      // undefined
  symbol: Symbol('x'),   // Symbol
  bigint: 123n,          // BigInt
}

// 序列化后:
JSON.stringify(data)
// { "date": "2024-01-15T10:30:00.000Z" }
// 函数、undefined、Symbol 会被忽略
// BigInt 会报错

序列化与反序列化

基本用法

typescript
// 序列化:对象 → 字符串
const user = { name: 'Alice', age: 25 }
const jsonString = JSON.stringify(user)
// '{"name":"Alice","age":25}'

// 反序列化:字符串 → 对象
const parsed = JSON.parse(jsonString)
// { name: 'Alice', age: 25 }

处理日期

typescript
// 问题:Date 序列化后变成字符串
const data = { createdAt: new Date() }
const json = JSON.stringify(data)
// '{"createdAt":"2024-01-15T10:30:00.000Z"}'

const parsed = JSON.parse(json)
parsed.createdAt  // 字符串,不是 Date!

// 解决方案 1:使用 reviver 函数
const parsed2 = JSON.parse(json, (key, value) => {
  if (key === 'createdAt') {
    return new Date(value)
  }
  return value
})

// 解决方案 2:使用 superjson(推荐)
import superjson from 'superjson'

const json2 = superjson.stringify({ date: new Date() })
const parsed3 = superjson.parse(json2)
// parsed3.date 是真正的 Date 对象

API 响应格式规范

统一的响应结构

typescript
// 成功响应
interface SuccessResponse<T> {
  success: true
  data: T
}

// 列表响应(带分页)
interface ListResponse<T> {
  success: true
  data: T[]
  pagination: {
    page: number
    pageSize: number
    total: number
    totalPages: number
  }
}

// 错误响应
interface ErrorResponse {
  success: false
  error: {
    code: string
    message: string
  }
}

实际示例

typescript
// 获取单个用户
// GET /api/users/123
{
  "success": true,
  "data": {
    "id": "123",
    "name": "Alice",
    "email": "alice@example.com"
  }
}

// 获取用户列表
// GET /api/users?page=1&pageSize=10
{
  "success": true,
  "data": [
    { "id": "1", "name": "Alice" },
    { "id": "2", "name": "Bob" }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 10,
    "total": 100,
    "totalPages": 10
  }
}

// 错误响应
// GET /api/users/999
{
  "success": false,
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "用户不存在"
  }
}

命名规范

前端常用 camelCase

typescript
// 前端 TypeScript
interface User {
  userId: string
  firstName: string
  lastName: string
  createdAt: string
}

后端可能用 snake_case

python
# Python/数据库
{
  "user_id": "123",
  "first_name": "Alice",
  "last_name": "Smith",
  "created_at": "2024-01-15T10:30:00Z"
}

转换方案

typescript
// 使用库进行转换
import camelcaseKeys from 'camelcase-keys'
import snakecaseKeys from 'snakecase-keys'

// 接收数据时:snake_case → camelCase
const apiResponse = await fetch('/api/users')
const data = camelcaseKeys(await apiResponse.json(), { deep: true })

// 发送数据时:camelCase → snake_case
const body = snakecaseKeys(userData, { deep: true })
await fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify(body),
})

觉知:常见问题

1. 循环引用

typescript
// ❌ 会报错
const obj: any = { name: 'Alice' }
obj.self = obj  // 循环引用

JSON.stringify(obj)  // TypeError: Converting circular structure to JSON

2. 忘记设置 Content-Type

typescript
// ❌ 服务器可能无法正确解析
fetch('/api/users', {
  method: 'POST',
  body: JSON.stringify(data),
})

// ✅ 必须设置 Content-Type
fetch('/api/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(data),
})

3. 数字精度丢失

typescript
// 大数字可能丢失精度
const bigNumber = 9007199254740993  // 超出 JS 安全整数范围
JSON.parse('{"id": 9007199254740993}')
// { id: 9007199254740992 }  精度丢失!

// 解决方案:用字符串传递大数字
{ "id": "9007199254740993" }

本节小结

要点说明
JSON.stringify对象转字符串
JSON.parse字符串转对象
Date 处理需要手动转换或用 superjson
Content-Type发送 JSON 必须设置
命名规范前后端约定一致