将FormData作为对象值发送POST请求时后端无法获取文件的问题
问题原因分析
- JSON无法序列化FormData对象:FormData是浏览器专门用于表单数据(含文件)的特殊对象,当你用
JSON.stringify(data)时,JSON序列化机制会将FormData直接转换为空对象{},所以后端接收到的uploads字段就是空对象,自然取不到文件数据。 - 请求头配置错误:你手动设置了
Content-Type: application/json,但实际要传输文件时,正确的请求格式应该是multipart/form-data,而直接发送JSON的方式根本无法承载二进制文件内容。
解决方案
方案一:将所有数据统一放入FormData(推荐,标准文件上传方式)
把普通字段和文件都追加到FormData中,直接发送FormData作为请求体,fetch会自动设置正确的multipart/form-data请求头。
修正后的代码:
// 先修正原代码的语法错误:Blob构造函数的字符串参数少了闭合单引号 const blob = new Blob(['some-image'], {type: 'image/jpeg'}); const formData = new FormData(); formData.append("file", blob); // 将普通字段也追加到FormData中 formData.append("name", "John"); formData.append("age", "24"); async postData() { try { const res = await fetch(endpoint, { method: 'POST', // 无需手动设置Content-Type,fetch会自动处理 body: formData, }); return res.status; } catch (error) { console.log(error) } }
如果后端需要把普通字段归类到uploads下,可以将普通字段打包成JSON字符串后追加:
formData.append("uploads[file]", blob); formData.append("uploads[name]", "John"); // 或者把非文件字段转成JSON字符串 formData.append("userInfo", JSON.stringify({name: 'John', age: '24'}));
后端拿到userInfo字段后再解析成JSON即可。
方案二:将Blob转为Base64嵌入JSON(仅适合小文件)
如果必须用JSON格式传输,可以将Blob转为Base64字符串,放入JSON对象中发送。但这种方式会让文件体积增大约30%,不适合大文件。
示例代码:
const blob = new Blob(['some-image'], {type: 'image/jpeg'}); // 工具函数:将Blob转为Base64 async function blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(blob); }); } async postData() { try { const base64Image = await blobToBase64(blob); const data = { name: 'John', age: '24', uploads: { file: base64Image, type: 'image/jpeg' } }; const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); return res.status; } catch (error) { console.log(error) } }
后端需要将接收到的Base64字符串解码回文件。
总结
不能直接将FormData作为JSON的一部分发送,因为JSON无法正确序列化FormData对象。推荐使用方案一,这是Web场景下文件上传的标准实现方式。
内容的提问来源于stack exchange,提问作者s.khan
相关产品推荐
相关产品推荐

