接口返回 JSON,运营同学要 CSV;历史 CSV 导回系统时,又要求恢复成 JSON。看上去只是两种格式之间互转,真正容易出问题的地方却在字段映射和类型判断上。
例如,订单号 000128 一旦被当成数字,导出后会变成 128;身份证号、长整型 ID 经过 JavaScript 或表格软件处理,可能已经失去原始精度;嵌套对象和数组放进二维表,也没有一个放之四海皆准的答案。
这一篇先把 JSON 与 CSV 互转时最常见的规则讲清楚。
一、JSON 是树,CSV 是表
JSON 可以表达对象、数组、字符串、数字、布尔值和 null。对象可以继续嵌套对象,数组里还能装数组。JSON 的语法和数据类型由 RFC 8259 定义。
CSV 则简单得多。它由行和列组成,单元格本质上是一段文本。CSV 没有统一的“数字列”“日期列”或“布尔列”定义,常见的逗号分隔和双引号转义约定可参考 RFC 4180。
先看一段典型接口响应:
{
"requestId": "a9d2f",
"data": {
"items": [
{
"orderId": "000128",
"amount": 99.5,
"paid": true,
"buyer": {
"name": "Li Hua",
"city": "Hangzhou"
},
"tags": ["new", "priority"]
}
]
}
}
CSV 不需要 requestId,真正的记录数组是 $.data.items。确定记录路径后,字段可以映射成:
| JSON 路径 | CSV 列名 | 示例值 |
|---|---|---|
orderId |
order_id |
000128 |
amount |
amount |
99.5 |
paid |
paid |
true |
buyer.name |
buyer_name |
Li Hua |
buyer.city |
buyer_city |
Hangzhou |
tags |
tags |
["new","priority"] |
这个表格里最值得注意的是 orderId。它看起来像数字,实际是标识符,必须保留为字符串。
二、JSON 转 CSV:先选记录,再处理嵌套字段
JSON 转 CSV 时,第一步不是“开始导出”,而是选定哪一个数组代表一行记录。
接口经常有一层或多层包装:
{
"code": 0,
"message": "ok",
"data": {
"page": 1,
"items": [
{
"id": 1, "name": "A" },
{
"id": 2, "name": "B" }
]
}
}
这里应选择 $.data.items,而不是把整个响应对象硬塞进一行 CSV。code、message、分页信息通常属于响应元数据,不属于业务记录。
嵌套对象适合展平为路径列:
{
"id": 1,
"profile": {
"email": "dev@example.com",
"region": "cn-hangzhou"
}
}
可以转成:
id,profile.email,profile.region
1,dev@example.com,cn-hangzhou
点路径容易读,也能避免不同层级的同名字段互相覆盖。
实际处理时,建议先扫描所有记录,得到列名并集。不能只根据第一行决定列,否则后续记录中才出现的字段会被悄悄丢掉。
function collectColumns(records) {
const columns = new Set();
for (const record of records) {
for (const key of Object.keys(record)) {
columns.add(key);
}
}
return [...columns];
}
这段示例只处理一层对象。生产环境还需要递归展平嵌套对象,并对最大深度、列数和输入大小设置限制。
需要快速验证记录路径、列并集和嵌套对象展平结果时,可使用 JSON to CSV Converter。它支持选择记录数组、调整列顺序,以及明确指定数组处理方式。
三、数组不要默认用逗号拼接
对象可以展平,数组却需要先决定业务含义。
例如标签:
{
"id": 1,
"tags": ["new", "priority"]
}
通常有三种处理方式。
第一种是保留为 JSON 文本:
id,tags
1,"[""new"",""priority""]"
信息最完整,后续也能可靠地还原数组。
第二种是连接为字符串:
id,tags
1,new|priority
阅读方便,但要先确认标签本身不会包含分隔符。将来再导回 JSON 时,也无法判断原始数组里是否有空值、嵌套数组或包含竖线的内容。
第三种是展开成多行:
id,tag
1,new
1,priority
适合一对多明细表。代价是原来的一条 JSON 记录变成多条 CSV 行,其他字段会重复出现。对于包含多个数组字段的对象,展开还可能产生笛卡尔积,行数很快失控。
数组如何导出不是格式问题,而是表结构设计问题。导出前先决定:这列是“一个文本字段”,还是“一个独立的明细表”。
四、CSV 转 JSON:默认字符串,比自动猜类型更可靠
CSV 没有类型信息。下面这一行:
order_id,enabled,total,ship_date
000128,true,99.50,2026-09-21
不看业务定义,无法断言:
000128是订单号,还是数值 128;true是布尔值,还是文本"true";99.50是否需要保留两位小数的显示形式;- 日期是否应转成 ISO 字符串、时间戳,还是继续保留原文本。
因此,CSV 转 JSON 的安全默认值应该是:所有单元格先保留为字符串。
[
{
"order_id": "000128",
"enabled": "true",
"total": "99.50",
"ship_date": "2026-09-21"
}
]
当字段定义明确时,再应用类型规则。例如:
const fieldRules = {
enabled: "boolean",
total: "decimal",
ship_date: "string",
order_id: "string"
};
对布尔值可以采用严格转换:
function parseBoolean(value) {
if (value === "true") return true;
if (value === "false") return false;
return value;
}
不要把 TRUE、yes、1、on 全部默认当成布尔值,除非导入规范明确这样约定。宽松推断在演示数据里显得方便,在真实数据里常常变成误判。
CSV to JSON Converter 采用保守的类型推断策略:默认保留字符串;开启推断后,才转换无歧义的安全数字、true、false 和 null。前导零值、日期、超出安全范围的长整数等容易误判的数据会保留为字符串。
五、长数字和前导零是最容易丢数据的两类字段
JavaScript 的安全整数范围有限。下面这个值已经超出 Number 能精确表达的范围:
9007199254740993
如果直接转成 JavaScript Number,可能变成:
9007199254740992
更麻烦的是,错误不会报出来。数据看起来仍然是一个合理的数字。
以下字段在 CSV 导入时通常都应该按字符串处理:
- 订单号、物流单号、证件号码;
- 手机号、银行卡号;
- 邮编、行政区划代码;
- 可能超过安全整数范围的业务 ID;
- 带前导零的编号。
金额也要谨慎。99.50 转成数字后通常会变成 99.5。如果字段表示可计算金额,业务系统可以转成最小货币单位或十进制定点类型;如果只是展示值或原始导出数据,保留字符串更稳妥。
六、CSV 的引号规则不能靠字符串拼接
CSV 里只要字段包含分隔符、双引号或换行,就需要正确引用。
例如:
name,remark
Alice,"包含逗号, 双引号 ""quoted"" 和换行
的备注"
双引号在字段内部要写成两个双引号。不能用 row.join(",") 直接拼接:
const row = ["Alice", "包含逗号, 的备注"];
console.log(row.join(","));
// Alice,包含逗号, 的备注
这样输出后,第二列会被错误拆成两列。
一个基础的转义函数可以这样写:
function escapeCsvCell(value, delimiter = ",") {
const text = String(value);
if (text.includes(delimiter) || /["\r\n]/.test(text)) {
return `"${
text.replaceAll('"', '""')}"`;
}
return text;
}
CSV 数据如果会被用户下载后在表格软件中打开,还要注意公式注入。以 =, +, -, @ 开头的单元格,部分软件可能当作公式执行。给这些单元格加前缀可以降低风险,但会改变导出的原始值,因此应由业务明确选择,不要默默修改数据。
七、一次可追溯的互转流程
无论 JSON 转 CSV,还是 CSV 转 JSON,都建议按这个顺序处理:
确认源数据结构
→ 明确字段映射
→ 定义类型规则
→ 预览转换结果
→ 抽样校验关键字段
→ 再下载或导入
重点检查这些字段:
- 前导零编号是否保持原样;
- 长 ID 是否发生精度变化;
- 空单元格导成
""、null还是缺失字段; - 数组是 JSON 文本、分隔字符串,还是多行明细;
- 含逗号、引号和换行的文本是否能往返还原;
- 表格软件打开 CSV 后,公式型内容是否被错误执行。
JSON 与 CSV 的互转从来不是“改个扩展名”。真正决定结果的,是字段代表什么、哪些值允许转类型、哪些信息必须原样保留。下一篇可以继续讨论表头清洗、空值策略、分隔符识别,以及如何把 CSV 导入规则变成可复用的数据契约。