使用Fetch API发送包含File属性的对象数组的正确方法
现有实现的核心问题
File、FormData都属于原生二进制相关对象,无法被JSON.stringify正常序列化,这类属性会在序列化时被直接丢弃,后端根本收不到文件内容。- 手动指定
Content-Type: application/json不符合文件上传的格式要求,哪怕序列化出了内容,后端也无法正确解析二进制数据。 getFileMeta中给单个文件套FormData后再塞回普通对象的逻辑完全多余,反而增加了不必要的复杂度。
正确实现方式
文件上传场景必须使用FormData作为请求体——JSON格式原生不支持二进制文件传输,这是Web规范的约定。针对你要传的对象数组结构,只要按FormData的嵌套命名规则组装字段即可,不需要手动设置请求头。
首先修正getFileMeta的多余逻辑,直接返回带原始File对象的结构化数据:
function getFileMeta(file) { let [article, date] = file.name.split("_"); date = date.split(".")[0]; // 排除.pdf后缀 return { name: article, date: date, file: file // 直接保留原始File对象即可,无需套FormData }; }
然后修改提交逻辑,统一组装FormData:
async function onSubmit(event) { event.preventDefault(); const files = Array.from(event.target.file.files); const validFiles = getOnlyValidFiles(files); if (!files.length || !validFiles.length) { console.log("No data to submit"); return; } const data = validFiles.map(getFileMeta); const formData = new FormData(); // 按数组索引组装嵌套字段,格式为 数组名[索引][字段名] data.forEach((item, index) => { formData.append(`items[${index}][name]`, item.name); formData.append(`items[${index}][date]`, item.date); formData.append(`items[${index}][file]`, item.file); }); const response = await fetch("/api/v1/upload/files", { method: "POST", // 不要手动设置Content-Type!浏览器会自动生成带boundary的正确请求头 body: formData, }); const json = await response.json(); console.log(json); }
补充说明
- 上面的
items[${index}][字段名]是通用的FormData嵌套数据约定,主流后端框架(Node.js的multer、Python的FastAPI/Django、Java的Spring等)都能自动解析为对应的对象数组,你可以根据后端的接口要求调整前缀(比如后端不需要items前缀的话,直接写${index}[字段名]即可)。如果你的字段名和示例里的name、date不一致,只要替换对应append的键名即可,和后端要求的字段名保持对齐就行。 - 只有当后端明确要求必须接收纯JSON格式时,才需要考虑把
File转成Base64字符串塞进JSON,但这种方式会增大30%左右的传输体积、有额外编解码开销,非必要不推荐。 - 一定不要手动给FormData请求设置
Content-Type,手动指定会覆盖浏览器自动生成的带边界标记(boundary)的请求头,直接导致后端无法解析请求内容。
内容的提问来源于stack exchange,提问作者Mario
相关产品推荐
相关产品推荐

