如何正确获取FormData文件数据并通过Ajax提交?
问题:表单上传文件时Ajax无法提交完整文件数据
我开发了一个允许用户同时上传音频文件和图片文件的表单,但测试时发现alert仅返回基础数据,未包含文件信息,文件字段显示为{}。想了解如何确保通过Ajax请求提交完整的文件数据。
前端React代码
function PodcastUpload({ data }) { function handleSubmit(e) { e.preventDefault(); const formData = new FormData(document.getElementById("podcastupload")); var json = JSON.stringify(Object.fromEntries(formData.entries())); alert(json); console.log('You clicked submit.'); } return (<> <h1>Upload New Episode</h1> <h2>{data}</h2> <form id="podcastupload" onSubmit={handleSubmit} > <input type="file" id="file" name="file" multiple></input> <input name="uuid" value="62569301efd5e89879d13b29"/> <input name="show_id" value="617414548b226e7231bfba5b"/> <input name="show_b" value="proptech"/> <input name="season" value="4"/> <input name="episode_no" value="40"/> <input name="title" value="test title"/> <textarea name="description"></textarea> <input name="explicit" value="false"/> <input type="date" name="pubDate"/> <input type="submit"/> </form> </>) }
Alert返回结果
{"file":{},"uuid":"62569301efd5e89879d13b29","show_id":"617414548b226e7231bfba5b","show_b":"proptech","season":"4","episode_no":"40","title":"test title","description":"","explicit":"false","pubDate":"2022-09-08"}
Postman生成的后端请求示例代码
var request = require('request'); var fs = require('fs'); var options = { 'method': 'POST', 'url': 'http://localhost:3000/api/podcasts/gupload', 'headers': { 'Cookie': 'next-auth.session-token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..OWf8yhLsBihBAl3N.EMeo_KcosE6QlogUi22Kps6z3lyeyQlk3vP9lNdyvlqDaA8SKOXJtpv3cfrAIVMn7CaBcLDKysAIy3KAFYWCYyFg3hpzwh6yNkTTn65Y_ktuH-N0u_sUCQ1i_dhhVTUHK-q3ck6ttzPIsfD_9YogHWj4ha2GaO72ukMval_7P8CN9OVt0ZBmBCbjyQY-UoZCeFi9qRRac994ReHy_oRUPeF3Cbv-4Nrm9G3MtK1A2X25YIRlDowiehQwFUU_8Kb1fcaEzFE.rm3d-QIASavADhiMmBqqzQ' }, formData: { 'file': { 'value': fs.createReadStream('/Users/russellharrower/Downloads/S04E02.png'), 'options': { 'filename': 'S04E02.png', 'contentType': null } }, 'file': { 'value': fs.createReadStream('/Users/russellharrower/Desktop/S04E02.mp3'), 'options': { 'filename': 'S04E02.mp3', 'contentType': null } }, 'uuid': '62569301efd5e89879d13b29', 'show_id': '617414548b226e7231bfba5b', 'show_b': 'Test', 'season': '4', 'episode_no': '2', 'title': 'Test', 'description': '<pTest</p>', 'explicit': 'false', 'pubDate': '2022-09-25T14:00:00+08:00' } }; request(options, function (error, response) { if (error) throw new Error(error); console.log(response.body); });
解决方案
1. 问题根源
你看到file字段显示为{},是因为File对象无法被JSON.stringify正确序列化——JSON只能处理基础类型,文件这类二进制对象转JSON后就变成空对象了。但实际上FormData对象里已经正确包含了文件数据,只是你转成JSON后看不到而已。
2. 正确的Ajax提交方式
不要将FormData转成JSON,直接发送FormData对象即可,浏览器会自动处理multipart/form-data格式的请求:
使用fetch的修改示例:
function handleSubmit(e) { e.preventDefault(); const formData = new FormData(document.getElementById("podcastupload")); // 直接发送FormData,无需转JSON fetch('http://localhost:3000/api/podcasts/gupload', { method: 'POST', credentials: 'include', // 自动携带登录Cookie,对应Postman里的Cookie头 body: formData }) .then(response => { if (!response.ok) throw new Error('请求失败'); return response.json(); }) .then(result => { console.log('上传成功:', result); // 这里可以做成功后的提示或跳转 }) .catch(err => { console.error('上传出错:', err); }); }
使用axios的修改示例(如果项目用axios):
import axios from 'axios'; function handleSubmit(e) { e.preventDefault(); const formData = new FormData(document.getElementById("podcastupload")); axios.post('http://localhost:3000/api/podcasts/gupload', formData, { withCredentials: true, // 携带Cookie // 不需要手动设置Content-Type,axios会自动添加正确的multipart/form-data及boundary }) .then(response => { console.log('上传成功:', response.data); }) .catch(error => { console.error('上传出错:', error); }); }
3. 关键注意事项
- 你的文件输入已经设置了
multiple,可以选择多个文件,FormData会自动将多个文件以同名file字段的形式提交,和Postman示例的格式一致,后端能正确接收。 - 不要手动设置
Content-Type: multipart/form-data,浏览器或axios会自动添加包含boundary的正确头信息,手动设置反而会导致请求格式错误。 - 如果需要携带登录状态的Cookie,要设置
credentials: 'include'(fetch)或withCredentials: true(axios)。
内容的提问来源于stack exchange,提问作者RussellHarrower
相关产品推荐
相关产品推荐

