尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

JavaScript 网络请求实战:FormData 对象详解与 multipart/form-data 表单提交

JavaScript 网络请求实战:FormData 对象详解与 multipart/form-data 表单提交 文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载本文是 Modern JavaScript Tutorialjavascript.infoNetwork requests 章节中 FormData 一节的完整实战指南系统讲解如何使用FormData对象捕获 HTML 表单、动态拼装字段并通过fetch以multipart/form-data编码发送普通表单、文件与二进制数据如 Canvas 生成的图片。读完本文你将掌握FormData的全部构造与操作方法、与fetch的配合方式以及文件上传场景下前端发送与后端解析的完整闭环。什么是 FormDataHTML 表单数据的 JavaScript 表示在网页应用中提交表单是一个高频需求发送纯文本字段、附带文件、追加额外的隐藏数据等等。传统做法是让浏览器整页刷新并完成表单提交而现代做法则是用 JavaScript 捕获表单数据、通过fetch异步发送整个过程不刷新页面。FormData正是为此设计的对象——它用于表示 HTML 表单数据。其核心构造方式如下let formData new FormData([form]);如果传入 HTML 的form元素它会自动捕获该表单内的所有字段包括input、select、textarea、input typefile等如果不传参数则创建一个空的FormData之后可以用方法手动追加字段。FormData最特别的地方在于网络方法如fetch可以直接把它作为请求体body接受。浏览器会自动将其编码并以Content-Type: multipart/form-data的 MIME 类型发送出去。从服务端的角度看这就和一次普通的 HTML 表单提交完全一样因此无需任何特殊适配。补充阅读FormData是 Fetch API 中body允许的四种类型之一——字符串如 JSON、FormData以multipart/form-data提交、Blob/BufferSource二进制数据、URLSearchParams以x-www-form-urlencoded提交较少用。此外Response对象还提供了response.formData()方法用于把响应体反向解析成FormData对象。发送一个简单的表单下面是最简单的表单提交示例。可以看到核心代码几乎就是一行form idformElem input typetext namename valueJohn input typetext namesurname valueSmith input typesubmit /form script formElem.onsubmit async (e) { e.preventDefault(); let response await fetch(/article/formdata/post/user, { method: POST, body: new FormData(formElem) }); let result await response.json(); alert(result.message); }; /script关键步骤拆解在表单的onsubmit事件处理器中调用e.preventDefault()阻止浏览器默认的整页提交行为构造new FormData(formElem)把整个表单的字段自动收集进FormData在fetch的options中指定method: POST并把FormData实例作为body传入通过await response.json()读取服务端返回的 JSON 结果。本例中服务端代码不在展示范围内它接收 POST 请求并返回User saved之类的消息。不过本仓库恰好提供了配套的服务端实现可以对照理解详见下文仓库中的服务端示例小节。FormData 的常用方法在FormData创建之后我们还可以用以下方法修改其中的字段方法说明formData.append(name, value)添加一个指定name和value的表单字段formData.append(name, blob, fileName)添加一个字段效果等同于表单中有input typefile第三个参数fileName设置的是文件名而非字段名相当于用户在文件系统中选中的那个文件名formData.delete(name)删除指定name的字段formData.get(name)获取指定name的字段值formData.has(name)判断是否存在指定name的字段存在返回true否则返回false需要特别留意HTML 表单在技术上允许出现多个同名name的字段因此多次调用append会不断追加同名字段而不是覆盖。与append语法相同但语义不同的还有set方法formData.set(name, value)formData.set(name, blob, fileName)set与append唯一的区别是.set会先移除所有指定name的字段再追加一个新字段从而保证该name只对应一个字段其余行为与append完全一致。此外FormData是可迭代对象可以用for..of循环遍历全部键值对let formData new FormData(); formData.append(key1, value1); formData.append(key2, value2); // 列出所有 key/value 对 for (let [name, value] of formData) { alert(${name} ${value}); // 先输出 key1 value1再输出 key2 value2 }发送带文件的表单由于FormData总是以multipart/form-data编码发送而这种编码天然支持二进制文件所以表单中的input typefile字段也会像普通表单提交一样被一并发送。示例form idformElem input typetext namefirstName valueJohn Picture: input typefile namepicture acceptimage/* input typesubmit /form script formElem.onsubmit async (e) { e.preventDefault(); let response await fetch(/article/formdata/post/user-avatar, { method: POST, body: new FormData(formElem) }); let result await response.json(); alert(result.message); }; /script这段代码把文本字段firstName与用户通过文件选择器选中的图片picture一起打包发送服务端收到的就是一个带图片的用户资料请求。用 FormData 发送 Blob 二进制数据在 Fetch 章节中我们已经知道动态生成的二进制数据例如一张图片可以很方便地作为Blob直接传给fetch的body参数。但在实际业务中往往更希望图片不是单独发送而是作为表单的一部分、连同name等附加元数据一起提交。这样做还有一个现实原因服务端通常更擅长解析 multipart 编码的表单而不是直接处理裸二进制流。下面这个例子演示了如何把canvas中绘制的图片转成Blob再连同其他字段以FormData表单形式提交body stylemargin:0 canvas idcanvasElem width100 height80 styleborder:1px solid/canvas input typebutton valueSubmit onclicksubmit() script canvasElem.onmousemove function(e) { let ctx canvasElem.getContext(2d); ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); }; async function submit() { let imageBlob await new Promise(resolve canvasElem.toBlob(resolve, image/png)); let formData new FormData(); formData.append(firstName, John); formData.append(image, imageBlob, image.png); let response await fetch(/article/formdata/post/image-form, { method: POST, body: formData }); let result await response.json(); alert(result.message); } /script /body重点看Blob是如何被追加到表单中的formData.append(image, imageBlob, image.png);这一行等价于表单中存在input typefile nameimage且用户从文件系统中选择了一个名为image.png第三个参数的文件其内容就是imageBlob第二个参数。服务端会把它当作一次普通表单提交来读取表单字段和文件。关于canvas.toBlob(resolve, image/png)这是 Canvas 标准的异步导出 API第一个回调参数接收生成的Blob第二个参数指定 MIME 类型为 PNG。用await包装 Promise 后即可拿到图片二进制数据。仓库中的服务端示例如何接收 multipart 表单本仓库在 5-network/02-formdata/post.view/server.js 中提供了与上述三个示例配套的 Node.jsKoa服务端可以帮助你验证前端发送的数据结构。三个路由分别对应三组示例POST /user简单的表单提交路由直接返回{ message: User saved }POST /user-avatar接收用户 头像的 multipart 请求使用busboyasync-busboy解析POST /image-form接收Canvas 图片 字段的 multipart 请求同样用busboy解析。以/image-form为例服务端解析逻辑如下router.post(/image-form, async (ctx) { let files []; const { fields } await busboy(ctx.req, { onFile(fieldname, file, filename, encoding, mimetype) { // 读取完整文件流以便继续处理 let length 0; file.on(data, function(data) { length data.length; }); file.on(end, () { files.push({ fieldname, filename, length }); }); } }); ctx.body { message: Image saved, firstName: ${fields.firstName}, Image size:${files[0].length}, fileName: ${files[0].filename} }; });通过这段代码可以印证前端行为的两个关键点字段与文件分离busboy解析后普通字段如firstName通过fields对象访问而文件通过onFile回调按流式stream读取文件名来自第三个参数files[0].filename输出的正是前端formData.append(image, imageBlob, image.png)中传入的image.png证实了append(name, blob, fileName)的第三个参数会被服务端当作真实文件名接收。与 XMLHttpRequest 的配合FormData并不只服务于fetch。在仓库的 XMLHttpRequest 章节中xhr.send(formData)是 POST 请求的标准用法let formData new FormData([form]); // 创建对象可选地从 form 填充 formData.append(name, value); // 追加一个字段 let xhr new XMLHttpRequest(); xhr.open(POST, /article/xmlhttprequest/post/user); xhr.send(formData);流程为创建FormData并从表单预填字段 → 用append追加额外字段如示例中的middle→xhr.open(POST, ...)→xhr.send(formData)。XHR同样会自动使用multipart/form-data编码发送。这说明FormData是浏览器网络 API 层通用的表单载体无论是fetch还是老牌的XMLHttpRequest都能直接消费它。小结FormData对象的用途是捕获 HTML 表单并借助fetch或其他网络方法将其提交出去。创建方式有两种new FormData(form)从 HTML 表单捕获或者直接new FormData()创建空对象再手动追加字段。字段操作方法一览formData.append(name, value)formData.append(name, blob, fileName)formData.set(name, value)formData.set(name, blob, fileName)formData.delete(name)formData.get(name)formData.has(name)两个必须记住的特性set会先移除同名字段再追加append不会这是二者唯一的区别由于 HTML 表单允许同名字段共存需要确保唯一时用set需要多值累积时用append。发送文件必须使用三参数语法append(name, blob, fileName)最后一个参数是文件名——对input typefile来说这个文件名通常取自用户的文件系统对动态生成的Blob如 Canvas 导出则需手动指定。理解以上内容后无论是简单表单、文件上传还是图片 元数据混合提交你都可以用FormData配合fetch在几行代码内完成且服务端无需任何特殊处理——因为它看到的始终是一次标准的 multipart 表单提交。赞分享文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载相关推荐vue-resource 实战配方Code RecipesFormData 表单提交与请求中止详解vue resource 实战配方Code RecipesFormData 表单提交与请求中止详解 本篇技术指南围绕 docs/recipes.md ht前端Playwright FormData用 APIRequestContext 构造 multipart/form-data 请求的完整指南Playwright FormData用 APIRequestContext 构造 multipart/form data 请求的完整指南 本文基于 Play测试开发工具浏览器控制如何使用HTTPie CLI发送多部分请求form-data和multipart完全指南如何使用HTTPie CLI发送多部分请求form data和multipart完全指南 HTTPie CLI是一款现代化、用户友好的命令行HTTP客户端特CLI开发工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表