news 2026/4/20 10:16:13

FormData 深入讲解教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FormData 深入讲解教程

FormData 是 HTML5 新增的内置对象,用于以键值对的形式封装表单数据,支持文件上传,可通过 XMLHttpRequest 或 Fetch API 异步提交,是前端处理表单数据(尤其是文件上传)的核心工具。本文从基础到进阶,全面讲解 FormData 的使用、原理和实战技巧。

一、FormData 核心特性

  1. 兼容性:支持所有现代浏览器(Chrome、Firefox、Edge、Safari 10+),IE10 及以上部分支持(需注意文件上传兼容性)。
  2. 核心能力
    • 模拟表单提交(multipart/form-data编码);
    • 动态添加/删除键值对,无需手动拼接字符串;
    • 支持文件/Blob 类型数据上传;
    • 可与 XMLHttpRequest、Fetch、Axios 无缝配合。
  3. 编码类型:默认采用multipart/form-data(表单上传文件的标准编码),区别于application/x-www-form-urlencoded(普通表单默认编码,不支持文件)。

二、基础用法

1. 创建 FormData 对象

方式1:空对象初始化

创建空的 FormData,手动添加键值对:

// 创建空 FormDataconstformData=newFormData();// 添加普通键值对(字符串/数字)formData.append('username','zhangsan');formData.append('age',25);// 添加布尔值(会自动转为字符串 "true"/"false")formData.append('isVip',true);
方式2:从 DOM 表单初始化

直接基于已有的<form>元素创建,自动封装所有表单字段:

<!-- HTML 表单 --><formid="myForm"><inputtype="text"name="username"value="lisi"><inputtype="number"name="age"value="30"><inputtype="file"name="avatar"><!-- 文件上传字段 --><inputtype="checkbox"name="hobby"value="coding"checked><inputtype="radio"name="gender"value="male"checked></form>
// 从表单元素初始化 FormDataconstform=document.getElementById('myForm');constformData=newFormData(form);// 此时 formData 已包含所有表单字段的键值对

2. 核心方法

FormData 提供了一套方法操作键值对,常用如下:

方法作用示例
append(key, value)添加键值对(支持重复键)formData.append('hobby', 'reading')
set(key, value)设置键值对(覆盖已有值)formData.set('username', 'wangwu')
get(key)获取指定键的第一个值formData.get('username')// “wangwu”
getAll(key)获取指定键的所有值(数组)formData.getAll('hobby')// [“coding”, “reading”]
delete(key)删除指定键的所有值formData.delete('age')
has(key)判断是否存在指定键formData.has('gender')// true
entries()返回迭代器,遍历所有键值对for (let [k, v] of formData.entries()) {}
keys()返回迭代器,遍历所有键for (let k of formData.keys()) {}
values()返回迭代器,遍历所有值for (let v of formData.values()) {}
关键区别:append vs set
  • append:允许同一个键对应多个值(如多选框),不会覆盖已有值;
  • set:会覆盖指定键的所有已有值,最终仅保留最新值。

示例:

constformData=newFormData();formData.append('tag','js');formData.append('tag','html');console.log(formData.getAll('tag'));// ["js", "html"]formData.set('tag','css');console.log(formData.getAll('tag'));// ["css"]

3. 遍历 FormData

FormData 是可迭代对象,支持多种遍历方式:

constformData=newFormData();formData.append('name','张三');formData.append('age',20);// 方式1:for...of 遍历 entriesfor(const[key,value]offormData){console.log(`${key}:${value}`);}// 方式2:forEachformData.forEach((value,key)=>{console.log(`${key}:${value}`);});// 方式3:遍历 keys/valuesfor(constkeyofformData.keys()){console.log('键:',key);}for(constvalueofformData.values()){console.log('值:',value);}

三、文件上传(核心场景)

FormData 最核心的用途是文件上传,支持单文件、多文件、大文件分片上传。

1. 单文件上传

步骤1:HTML 布局
<inputtype="file"id="fileInput"accept="image/*"><buttonid="uploadBtn">上传文件</button>
步骤2:JS 处理上传
constfileInput=document.getElementById('fileInput');constuploadBtn=document.getElementById('uploadBtn');uploadBtn.addEventListener('click',async()=>{// 获取选中的文件constfile=fileInput.files[0];if(!file){alert('请选择文件');return;}// 创建 FormData 并添加文件constformData=newFormData();formData.append('file',file);// 键名 "file" 需与后端接口约定formData.append('desc','用户头像');// 可同时添加其他参数try{// 发送请求(Fetch API)constresponse=awaitfetch('/api/upload',{method:'POST',body:formData,// FormData 作为 body,自动设置 Content-Type: multipart/form-data// 无需手动设置 Content-Type,浏览器会自动添加边界符(boundary)});constresult=awaitresponse.json();console.log('上传成功:',result);}catch(error){console.error('上传失败:',error);}});

2. 多文件上传

只需将 input 的multiple属性设为 true,然后遍历 files 数组添加:

<inputtype="file"id="multiFileInput"multipleaccept="image/*"><buttonid="multiUploadBtn">批量上传</button>
constmultiFileInput=document.getElementById('multiFileInput');constmultiUploadBtn=document.getElementById('multiUploadBtn');multiUploadBtn.addEventListener('click',async()=>{constfiles=multiFileInput.files;if(files.length===0){alert('请选择文件');return;}constformData=newFormData();// 遍历多文件,添加到同一个键(后端接收数组)for(leti=0;i<files.length;i++){formData.append('files',files[i]);// 键名统一为 "files"}// 发送请求constresponse=awaitfetch('/api/multi-upload',{method:'POST',body:formData,});constresult=awaitresponse.json();console.log('批量上传成功:',result);});

3. 上传进度监控

通过 XMLHttpRequest 可监控文件上传进度(Fetch API 需结合 ReadableStream,较复杂):

constfileInput=document.getElementById('fileInput');fileInput.addEventListener('change',()=>{constfile=fileInput.files[0];if(!file)return;constformData=newFormData();formData.append('file',file);constxhr=newXMLHttpRequest();xhr.open('POST','/api/upload');// 监控上传进度xhr.upload.addEventListener('progress',(e)=>{if(e.lengthComputable){constprogress=(e.loaded/e.total)*100;console.log(`上传进度:${progress.toFixed(2)}%`);}});// 上传完成回调xhr.addEventListener('load',()=>{if(xhr.status>=200&&xhr.status<300){console.log('上传成功:',JSON.parse(xhr.responseText));}else{console.error('上传失败');}});// 发送请求xhr.send(formData);});

四、与主流库配合使用

1. Axios 中使用 FormData

Axios 会自动识别 FormData,无需手动设置 Content-Type:

importaxiosfrom'axios';// 单文件上传asyncfunctionuploadFile(file){constformData=newFormData();formData.append('file',file);formData.append('name','测试文件');try{constresponse=awaitaxios.post('/api/upload',formData,{// 监控上传进度onUploadProgress:(e)=>{constprogress=(e.loaded/e.total)*100;console.log(`进度:${progress}%`);},headers:{// 无需设置 Content-Type,Axios 会自动添加 boundary// "Content-Type": "multipart/form-data"}});returnresponse.data;}catch(error){console.error('上传失败:',error);}}

2. React/Vue 中使用 FormData

以 React 为例(Vue 逻辑一致):

import React, { useRef } from 'react'; import axios from 'axios'; function UploadComponent() { const fileInputRef = useRef(null); const handleUpload = async () => { const file = fileInputRef.current.files[0]; if (!file) return; const formData = new FormData(); formData.append('file', file); await axios.post('/api/upload', formData); }; return ( <div> <input type="file" ref={fileInputRef} /> <button onClick={handleUpload}>上传</button> </div> ); }

五、常见问题与解决方案

1. 手动设置 Content-Type 导致上传失败

问题:手动设置Content-Type: multipart/form-data后,浏览器不会自动添加边界符(boundary),后端无法解析。
解决方案:不手动设置 Content-Type,让浏览器/Axios 自动生成(包含 boundary)。

2. 文件大小限制

问题:大文件上传超时/失败。
解决方案

  • 前端:分片上传(将文件切分成多个 Blob,分批上传);
  • 后端:配置文件大小限制(如 Node.js/Express 需设置express-fileuploadlimits)。

3. 跨域上传文件

问题:跨域时请求被拦截。
解决方案

  • 后端配置 CORS:允许Content-Type: multipart/form-data,并允许OPTIONS预检请求;
  • 前端请求时无需额外配置(Fetch/Axios 自动处理)。

4. FormData 无法打印/调试

问题console.log(formData)只能看到空对象,无法直接查看内容。
解决方案

// 方式1:遍历打印formData.forEach((v,k)=>console.log(k,v));// 方式2:转为对象(仅适用于非文件类型,文件会显示 [object File])constformDataObj=Object.fromEntries(formData.entries());console.log(formDataObj);

六、进阶技巧

1. 分片上传大文件

核心思路:将文件按固定大小切分,分批上传,后端合并:

asyncfunctionsliceUpload(file){constchunkSize=1024*1024;// 1MB 每片consttotalChunks=Math.ceil(file.size/chunkSize);constfileHash=Date.now()+'-'+file.name;// 唯一标识文件for(letchunkIndex=0;chunkIndex<totalChunks;chunkIndex++){// 切分文件conststart=chunkIndex*chunkSize;constend=Math.min(start+chunkSize,file.size);constchunk=file.slice(start,end);// 创建 FormDataconstformData=newFormData();formData.append('chunk',chunk);formData.append('chunkIndex',chunkIndex);formData.append('totalChunks',totalChunks);formData.append('fileHash',fileHash);formData.append('fileName',file.name);// 上传分片awaitfetch('/api/upload-chunk',{method:'POST',body:formData,});}// 所有分片上传完成,通知后端合并awaitfetch('/api/merge-chunk',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({fileHash,fileName,totalChunks}),});}

2. 自定义 Blob 上传

除了文件,还可以上传自定义 Blob(如生成的文本、图片):

// 上传自定义文本 BlobconsttextBlob=newBlob(['Hello FormData'],{type:'text/plain'});constformData=newFormData();formData.append('textFile',textBlob,'custom.txt');// 第三个参数为文件名fetch('/api/upload',{method:'POST',body:formData,});

七、后端接收示例(Node.js/Express)

以 Express 为例,使用multer处理 FormData 上传的文件:

constexpress=require('express');constmulter=require('multer');constapp=express();// 配置文件存储路径conststorage=multer.diskStorage({destination:(req,file,cb)=>{cb(null,'./uploads');// 上传文件保存目录},filename:(req,file,cb)=>{cb(null,Date.now()+'-'+file.originalname);// 重命名文件}});constupload=multer({storage});// 单文件上传接口app.post('/api/upload',upload.single('file'),(req,res)=>{// req.file 是上传的文件信息// req.body 是 FormData 中的其他参数(如 desc)res.json({code:200,msg:'上传成功',file:req.file,body:req.body});});// 多文件上传接口app.post('/api/multi-upload',upload.array('files',5),(req,res)=>{// req.files 是多文件数组res.json({code:200,msg:'批量上传成功',files:req.files});});app.listen(3000,()=>{console.log('服务器运行在 http://localhost:3000');});

八、总结

FormData 是前端处理表单数据(尤其是文件上传)的核心工具,核心要点:

  1. 优先使用append添加数据,set用于覆盖;
  2. 上传文件时无需手动设置Content-Type,避免丢失 boundary;
  3. 结合 XMLHttpRequest 监控上传进度,结合 Axios 简化请求;
  4. 大文件上传推荐分片策略,解决超时/失败问题;
  5. 后端需对应配置文件解析(如 Express + multer)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 15:43:48

基于Django的视频论坛系统的设计与实现(源码+lw+远程部署)

目录&#xff1a; 博主介绍&#xff1a; 完整视频演示&#xff1a; 系统技术介绍&#xff1a; 后端Java介绍 前端框架Vue介绍 具体功能截图&#xff1a; 部分代码参考&#xff1a; Mysql表设计参考&#xff1a; 项目测试&#xff1a; 项目论文&#xff1a;​ 为…

作者头像 李华
网站建设 2026/4/19 9:48:27

FaceFusion在心理治疗中的辅助作用研究设想

FaceFusion在心理治疗中的辅助作用研究设想 在临床心理干预实践中&#xff0c;一个长期存在的难题是&#xff1a;许多患者——尤其是儿童、创伤幸存者或社交障碍个体——难以通过语言准确表达内在情绪与自我认知。传统的谈话疗法依赖于言语叙述&#xff0c;但当一个人连“我是谁…

作者头像 李华
网站建设 2026/4/17 12:29:28

KCP协议:重新定义实时传输的游戏规则

KCP协议&#xff1a;重新定义实时传输的游戏规则 【免费下载链接】kcp KCP —— 这是一种快速且高效的自动重传请求&#xff08;Automatic Repeat-reQuest&#xff0c;简称ARQ&#xff09;协议&#xff0c;旨在提高网络数据传输的速度和可靠性。 项目地址: https://gitcode.c…

作者头像 李华
网站建设 2026/4/17 21:52:35

解锁机器学习全流程:一站式开发环境ML Workspace深度体验

机器学习工作空间&#xff08;ML Workspace&#xff09;是一个革命性的Web-based集成开发环境&#xff0c;专门为数据科学家和机器学习工程师量身打造。这个强大的平台集成了从数据处理、模型训练到部署监控的全套工具链&#xff0c;让复杂的数据科学任务变得简单高效。无论你是…

作者头像 李华
网站建设 2026/4/18 2:35:03

【限时干货】从入门到精通Open-AutoGLM:无代码自动化落地的6大核心要点

第一章&#xff1a;Open-AutoGLM无代码自动化初探Open-AutoGLM 是一个面向自然语言处理任务的开源无代码自动化框架&#xff0c;旨在降低大模型应用开发门槛。通过可视化界面与智能流程编排&#xff0c;用户无需编写代码即可完成从数据预处理到模型部署的全流程操作。核心特性 …

作者头像 李华
网站建设 2026/4/17 14:04:32

7天深度掌握C++编程:Accelerated C++实战进阶指南

7天深度掌握C编程&#xff1a;Accelerated C实战进阶指南 【免费下载链接】AcceleratedC中文英文两版高清下载介绍 Accelerated C 是一本备受推崇的编程书籍&#xff0c;专为具备C或C基础的读者设计&#xff0c;旨在快速提升编程水平。通过高效的讲解方式&#xff0c;本书深入浅…

作者头像 李华