news 2026/2/17 2:40:44

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/2/15 0:16:39

Open-AutoGLM免Root安装终极指南(仅限高级玩家的隐藏方案)

第一章&#xff1a;Open-AutoGLM免Root使用全景解析Open-AutoGLM 是一款基于轻量级自动化框架设计的智能辅助工具&#xff0c;专为无需 Root 权限的 Android 设备优化。它利用无障碍服务与 Intent 机制实现应用间协同控制&#xff0c;可在不破坏系统安全策略的前提下完成任务自…

作者头像 李华
网站建设 2026/2/12 9:18:41

YOLOv9性能优化与部署实战:从瓶颈诊断到效率跃迁

YOLOv9性能优化与部署实战&#xff1a;从瓶颈诊断到效率跃迁 【免费下载链接】yolov9 项目地址: https://gitcode.com/GitHub_Trending/yo/yolov9 在工业质检、自动驾驶等实时性要求极高的场景中&#xff0c;YOLOv9作为当前最先进的目标检测模型&#xff0c;其原生PyTo…

作者头像 李华
网站建设 2026/2/14 17:36:10

【远程控制新纪元】:基于Open-AutoGLM的WiFi手机操控系统搭建全过程

第一章&#xff1a;远程控制新纪元的开启随着云计算、物联网和5G网络的普及&#xff0c;远程控制技术正迎来前所未有的发展契机。设备间的无缝连接与实时交互已成为现代IT基础设施的核心需求。无论是远程办公、工业自动化&#xff0c;还是智能家居管理&#xff0c;高效的远程控…

作者头像 李华
网站建设 2026/2/15 10:08:56

Dracula主题终极指南:30分钟打造专属深色编程环境

Dracula主题终极指南&#xff1a;30分钟打造专属深色编程环境 【免费下载链接】dracula-theme &#x1f9db;&#x1f3fb;‍♂️ One theme. All platforms. 项目地址: https://gitcode.com/gh_mirrors/dr/dracula-theme 你是否厌倦了刺眼的白色编程界面&#xff1f;Dr…

作者头像 李华
网站建设 2026/2/16 2:09:59

第6篇 | OLT:藏在“小黑屋”里的接入网“司令部”

《固定接入网:光纤的“最后一公里”》 第6篇 01. 引子:深夜的“网络悬案”与背后的隐形大佬 先问你一个扎心的问题: 当你在工作日的晚上八九点,正开着重要的视频会议,或者全家人一起刷剧、打游戏时,突然网络开始“转圈圈”,视频卡成了PPT。你第一反应是怪谁? 99% 的…

作者头像 李华
网站建设 2026/2/16 15:34:32

Chipsbank APTool V7200终极指南:U盘量产与修复完整教程

还在为U盘批量生产而烦恼吗&#xff1f;Chipsbank APTool V7200作为专为Chipsbank控制芯片设计的量产工具&#xff0c;为您提供了一站式的解决方案。这款发布于2020年2月21日的专业工具&#xff0c;让U盘的格式化、固件升级和个性化定制变得前所未有的简单高效。 【免费下载链接…

作者头像 李华