FormData 文件上传如何转换为 JSON 格式?
在 Web 开发中,FormData 是用于模拟表单数据(含文件)提交的常用 API,但它的数据格式与 JSON 不同——FormData 是键值对集合,而 JSON 是文本化的结构化数据,若需将 FormData 文件上传相关的数据转换为 JSON,需根据场景区分处理:是否需要保留文件内容?以下是具体方法和注意事项。
为什么需要将 FormData 转为 JSON?
FormData 转为 JSON 的场景包括:
- 接口调试:某些 API 接口要求 JSON 格式参数,需提前查看
FormData的数据结构; - 数据存储:需将表单数据(含文件元信息)以 JSON 形式存入数据库或本地;
- 跨平台传输:JSON 是通用的数据交换格式,便于非 Web 端(如移动端、后端服务)解析。
FormData 转为 JSON 的核心思路
FormData 本质是一个键值对集合(key/value),value 可能是字符串、数字、文件(Blob/File)等,转换为 JSON 时,需解决两个核心问题:
- 文件如何表示:JSON 无法直接存储二进制文件,需转为文本(如 Base64)或保留文件元信息(如名称、大小、类型);
- 结构化处理:将
FormData的键值对映射为 JSON 的键值结构。
具体转换方法
方法 1:仅保留文件元信息(不包含文件内容)
如果不需要文件的实际内容,只需保留文件的名称、大小、类型等元数据,可直接遍历 FormData 的键值对,将文件对象转为元信息对象。
示例代码:
// 假设有一个 FormData 实例,包含文本字段和文件字段
const formData = new FormData();
formData.append('username', 'john');
formData.append('age', 25);
formData.append('avatar', new File(['file content'], 'avatar.jpg', { type: 'image/jpeg' }));
// 转换函数
function formDataToJsonWithMeta(formData) {
const json = {};
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
// 文件字段转为元信息对象
json[key] = {
type: 'file',
name: value.name,
size: value.size,
type: value.type,
lastModified: value.lastModified,
};
} else {
// 非文件字段直接存储
json[key] = value;
}
}
return json;
}
// 调用转换
const jsonData = formDataToJsonWithMeta(formData);
console.log(jsonData);
输出结果:
{
"username": "john",
"age": 25,
"avatar": {
"type": "file",
"name": "avatar.jpg",
"size": 12, // 文件内容字节数
"type": "image/jpeg",
"lastModified": 1625097600000 // 时间戳
}
}
适用场景:
仅需传递文件的基本信息,不涉及文件内容传输(如文件列表预览、元数据校验)。
方法 2:文件内容转为 Base64(包含文件内容)
如果需要保留文件的实际内容,可将文件对象通过 FileReader 读取为 Base64 编码的字符串,再存入 JSON。
示例代码:
// 假设 formData 同上
async function formDataToJsonWithBase64(formData) {
const json = {};
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
// 读取文件为 Base64
const base64 = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(value);
});
json[key] = {
type: 'file',
name: value.name,
size: value.size,
type: value.type,
content: base64, // Base64 编码内容
};
} else {
json[key] = value;
}
}
return json;
}
// 调用转换(需 async 环境)
(async () => {
const jsonData = await formDataToJsonWithBase64(formData);
console.log(jsonData);
})();
输出结果:
{
"username": "john",
"age": 25,
"avatar": {
"type": "file",
"name": "avatar.jpg",
"size": 12,
"type": "image/jpeg",
"content": "data:image/jpeg;base64,ZmlsZSBjb250ZW50" // Base64 编码的文件内容
}
}
注意事项:
- Base64 增大体积:文件转为 Base64 后,体积约增大 33%(每 3 字节转为 4 个 Base64 字符),大文件传输时需谨慎;
- 性能问题:大文件读取为 Base64 是异步操作,可能阻塞主线程,建议分片处理;
- 安全性:Base64 字符串较长,需注意传输过程中的数据截断或泄露风险。
方法 3:分片处理大文件(避免内存溢出)
对于大文件(如视频、高清图片),直接转为 Base64 可能导致内存溢出,可将其分片读取,每片转为 Base64 后拼接,或直接存储分片信息。
示例代码(分片读取为 Base64):
async function formDataToJsonWithChunkedBase64(formData, chunkSize = 1024 * 1024) {
const json = {};
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
const chunks = [];
const totalChunks = Math.ceil(value.size / chunkSize);
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, value.size);
const chunk = value.slice(start, end);
const base64 = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsDataURL(chunk);
});
chunks.push({ index: i, data: base64 });
}
json[key] = {
type: 'file',
name: value.name,
size: value.size,
type: value.type,
chunks: chunks, // 分片 Base64 数据
chunkSize: chunkSize,
};
} else {
json[key] = value;
}
}
return json;
}
// 调用示例
(async () => {
const jsonData = await formDataToJsonWithChunkedBase64(formData);
console.log(jsonData);
})();
输出结果(简化):
{
"avatar": {
"type": "file",
"name": "large_video.mp4",
"size": 10485760, // 10MB
"type": "video/mp4",
"chunkSize": 1048576, // 1MB/片
"chunks": [
{ "index": 0, "data": "data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28..." },
{ "index": 1, "data": "data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28..." },
// ... 共 10 个分片
]
}
}
适用场景:
大文件上传时需保留内容,同时避免内存溢出(如视频编辑、云存储场景)。
反向转换:JSON 转 FormData(回填表单)
若需将 JSON 数据重新转为 FormData(如回填表单并重新提交),可编写反向转换函数:
示例代码:
function jsonToFormData(json) {
const formData = new FormData();
for (const [key, value] of Object.entries(json)) {
if (value?.type === 'file' && value.content) {
// Base64 转 File(需处理 data URL 前缀)
const base64Data = value.content.split(',')[1]; // 去掉 "data:type;base64," 前缀
const binaryString = atob(base64Data); // Base64 解码为二进制字符串
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const file = new File([bytes], value.name, { type: value.type });
formData.append(key, file);
} else if (value?.type === 'file' && value.chunks) {
// 分片数据合并(需额外逻辑)
console.warn('分片文件合并暂未实现');


还没有评论,来说两句吧...