2026/3/26 4:14:45
网站建设
项目流程
公积金网站 如何做减员,百度网盘资源分享,十大免费壁纸软件,网站qq登录原理FormData 是 HTML5 新增的内置对象#xff0c;用于以键值对的形式封装表单数据#xff0c;支持文件上传#xff0c;可通过 XMLHttpRequest 或 Fetch API 异步提交#xff0c;是前端处理表单数据#xff08;尤其是文件上传#xff09;的核心工具。本文从基础到进阶#x…FormData 是 HTML5 新增的内置对象用于以键值对的形式封装表单数据支持文件上传可通过 XMLHttpRequest 或 Fetch API 异步提交是前端处理表单数据尤其是文件上传的核心工具。本文从基础到进阶全面讲解 FormData 的使用、原理和实战技巧。一、FormData 核心特性兼容性支持所有现代浏览器Chrome、Firefox、Edge、Safari 10IE10 及以上部分支持需注意文件上传兼容性。核心能力模拟表单提交multipart/form-data编码动态添加/删除键值对无需手动拼接字符串支持文件/Blob 类型数据上传可与 XMLHttpRequest、Fetch、Axios 无缝配合。编码类型默认采用multipart/form-data表单上传文件的标准编码区别于application/x-www-form-urlencoded普通表单默认编码不支持文件。二、基础用法1. 创建 FormData 对象方式1空对象初始化创建空的 FormData手动添加键值对// 创建空 FormDataconstformDatanewFormData();// 添加普通键值对字符串/数字formData.append(username,zhangsan);formData.append(age,25);// 添加布尔值会自动转为字符串 true/falseformData.append(isVip,true);方式2从 DOM 表单初始化直接基于已有的form元素创建自动封装所有表单字段!-- HTML 表单 --formidmyForminputtypetextnameusernamevaluelisiinputtypenumbernameagevalue30inputtypefilenameavatar!-- 文件上传字段 --inputtypecheckboxnamehobbyvaluecodingcheckedinputtyperadionamegendervaluemalechecked/form// 从表单元素初始化 FormDataconstformdocument.getElementById(myForm);constformDatanewFormData(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)// trueentries()返回迭代器遍历所有键值对for (let [k, v] of formData.entries()) {}keys()返回迭代器遍历所有键for (let k of formData.keys()) {}values()返回迭代器遍历所有值for (let v of formData.values()) {}关键区别append vs setappend允许同一个键对应多个值如多选框不会覆盖已有值set会覆盖指定键的所有已有值最终仅保留最新值。示例constformDatanewFormData();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. 遍历 FormDataFormData 是可迭代对象支持多种遍历方式constformDatanewFormData();formData.append(name,张三);formData.append(age,20);// 方式1for...of 遍历 entriesfor(const[key,value]offormData){console.log(${key}:${value});}// 方式2forEachformData.forEach((value,key){console.log(${key}:${value});});// 方式3遍历 keys/valuesfor(constkeyofformData.keys()){console.log(键,key);}for(constvalueofformData.values()){console.log(值,value);}三、文件上传核心场景FormData 最核心的用途是文件上传支持单文件、多文件、大文件分片上传。1. 单文件上传步骤1HTML 布局inputtypefileidfileInputacceptimage/*buttoniduploadBtn上传文件/button步骤2JS 处理上传constfileInputdocument.getElementById(fileInput);constuploadBtndocument.getElementById(uploadBtn);uploadBtn.addEventListener(click,async(){// 获取选中的文件constfilefileInput.files[0];if(!file){alert(请选择文件);return;}// 创建 FormData 并添加文件constformDatanewFormData();formData.append(file,file);// 键名 file 需与后端接口约定formData.append(desc,用户头像);// 可同时添加其他参数try{// 发送请求Fetch APIconstresponseawaitfetch(/api/upload,{method:POST,body:formData,// FormData 作为 body自动设置 Content-Type: multipart/form-data// 无需手动设置 Content-Type浏览器会自动添加边界符boundary});constresultawaitresponse.json();console.log(上传成功,result);}catch(error){console.error(上传失败,error);}});2. 多文件上传只需将 input 的multiple属性设为 true然后遍历 files 数组添加inputtypefileidmultiFileInputmultipleacceptimage/*buttonidmultiUploadBtn批量上传/buttonconstmultiFileInputdocument.getElementById(multiFileInput);constmultiUploadBtndocument.getElementById(multiUploadBtn);multiUploadBtn.addEventListener(click,async(){constfilesmultiFileInput.files;if(files.length0){alert(请选择文件);return;}constformDatanewFormData();// 遍历多文件添加到同一个键后端接收数组for(leti0;ifiles.length;i){formData.append(files,files[i]);// 键名统一为 files}// 发送请求constresponseawaitfetch(/api/multi-upload,{method:POST,body:formData,});constresultawaitresponse.json();console.log(批量上传成功,result);});3. 上传进度监控通过 XMLHttpRequest 可监控文件上传进度Fetch API 需结合 ReadableStream较复杂constfileInputdocument.getElementById(fileInput);fileInput.addEventListener(change,(){constfilefileInput.files[0];if(!file)return;constformDatanewFormData();formData.append(file,file);constxhrnewXMLHttpRequest();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.status200xhr.status300){console.log(上传成功,JSON.parse(xhr.responseText));}else{console.error(上传失败);}});// 发送请求xhr.send(formData);});四、与主流库配合使用1. Axios 中使用 FormDataAxios 会自动识别 FormData无需手动设置 Content-Typeimportaxiosfromaxios;// 单文件上传asyncfunctionuploadFile(file){constformDatanewFormData();formData.append(file,file);formData.append(name,测试文件);try{constresponseawaitaxios.post(/api/upload,formData,{// 监控上传进度onUploadProgress:(e){constprogress(e.loaded/e.total)*100;console.log(进度${progress}%);},headers:{// 无需设置 Content-TypeAxios 会自动添加 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 typefile 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-fileupload的limits。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]constformDataObjObject.fromEntries(formData.entries());console.log(formDataObj);六、进阶技巧1. 分片上传大文件核心思路将文件按固定大小切分分批上传后端合并asyncfunctionsliceUpload(file){constchunkSize1024*1024;// 1MB 每片consttotalChunksMath.ceil(file.size/chunkSize);constfileHashDate.now()-file.name;// 唯一标识文件for(letchunkIndex0;chunkIndextotalChunks;chunkIndex){// 切分文件conststartchunkIndex*chunkSize;constendMath.min(startchunkSize,file.size);constchunkfile.slice(start,end);// 创建 FormDataconstformDatanewFormData();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如生成的文本、图片// 上传自定义文本 BlobconsttextBlobnewBlob([Hello FormData],{type:text/plain});constformDatanewFormData();formData.append(textFile,textBlob,custom.txt);// 第三个参数为文件名fetch(/api/upload,{method:POST,body:formData,});七、后端接收示例Node.js/Express以 Express 为例使用multer处理 FormData 上传的文件constexpressrequire(express);constmulterrequire(multer);constappexpress();// 配置文件存储路径conststoragemulter.diskStorage({destination:(req,file,cb){cb(null,./uploads);// 上传文件保存目录},filename:(req,file,cb){cb(null,Date.now()-file.originalname);// 重命名文件}});constuploadmulter({storage});// 单文件上传接口app.post(/api/upload,upload.single(file),(req,res){// req.file 是上传的文件信息// req.body 是 FormData 中的其他参数如 descres.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 是前端处理表单数据尤其是文件上传的核心工具核心要点优先使用append添加数据set用于覆盖上传文件时无需手动设置Content-Type避免丢失 boundary结合 XMLHttpRequest 监控上传进度结合 Axios 简化请求大文件上传推荐分片策略解决超时/失败问题后端需对应配置文件解析如 Express multer。