
axios HTML 表单提交实战postForm、字段名路径记法与 JSON 转换原理【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axiosaxios 除了传统的post方法外还提供了专门用于表单提交的postForm/putForm/patchForm快捷方法可以直接把页面上的form元素作为请求体发送也可以在显式指定Content-Type: application/json时将其序列化为 JSON。本文以官方文档 HTML form posting (browser) 为主线结合当前仓库源码讲清楚 HTML 表单提交的三种用法、字段名路径记法dot / bracket notation的解析规则以及底层transformRequest、formDataToJSON的完整调用链。一、用 postForm 直接提交 HTML 表单当页面上已经存在一个form元素时无需手动构造FormData也无需编写任何取值的 JavaScript 代码只需用document.querySelector拿到表单元素传给axios.postForm即可await axios.postForm(https://your.server/api/post, document.querySelector(#htmlForm));postForm的语义是发送 multipart 表单数据。从源码看它并不是一个独立实现而是在Axios类初始化时由post/put/patch三个方法统一生成的姊妹方法——生成时会额外注入一个默认的Content-Type: multipart/form-data请求头见 lib/core/Axios.jsutils.forEach([post, put, patch, query], function forEachMethodWithData(method) { function generateHTTPMethod(isForm) { return function httpMethod(url, data, config) { return this.request( mergeConfig(config || {}, { method, headers: isForm ? { Content-Type: multipart/form-data, } : {}, url, data, }) ); }; } Axios.prototype[method] generateHTTPMethod(); // query 是幂等读方法multipart 表单体不符合其语义因此不生成 queryForm if (method ! query) { Axios.prototype[method Form] generateHTTPMethod(true); } });也就是说postForm、putForm、patchForm三者等价于对应方法 multipart/form-data内容类型唯一不生成*Form变体的是query源码注释说明这是出于幂等读方法的语义考虑。二、HTML 表单在 transformRequest 中如何变成 FormDatapostForm只是设置了内容类型真正把HTMLFormElement转成FormData的动作发生在默认请求转换器里见 lib/defaults/index.jstransformRequest: [ function transformRequest(data, headers) { const contentType headers.getContentType() || ; const hasJSONContentType contentType.indexOf(application/json) -1; const isObjectPayload utils.isObject(data); if (isObjectPayload utils.isHTMLForm(data)) { data new FormData(data); // 关键HTML 表单元素 → FormData } const isFormData utils.isFormData(data); if (isFormData) { return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data; } // ...其余分支ArrayBuffer / Blob / URLSearchParams / 对象序列化等 }, ],这段代码解释了文档中两种提交方式的完整行为表单以 multipart 形式提交HTMLFormElement先被new FormData(data)转换随后因内容类型不是 JSON 而原样返回FormData由xhr/fetch适配器负责带上multipart/form-data的 boundary 发送表单以 JSON 形式提交若内容类型包含application/json则FormData会被formDataToJSON转换成普通对象后再JSON.stringify。其中utils.isHTMLForm是基于Object.prototype.toString的kindOfTest(HTMLFormElement)类型探测见 lib/utils.js这也是该功能被标注为仅浏览器的原因——HTMLFormElement只存在于浏览器环境。三、把 FormData / HTMLForm 显式提交为 JSON文档给出的第二种用法是显式把Content-Type设为application/json普通axios.post也能直接提交FormData或form元素await axios.post(https://your.server/api/post, document.querySelector(#htmlForm), { headers: { Content-Type: application/json, }, });走的是上文transformRequest中hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data这条分支。除了随请求隐式触发axios 还在实例上暴露了可直接调用的工具方法axios.formToJSON见 lib/axios.js它接收HTMLFormElement或FormData内部同样先统一转成FormData再交给formDataToJSONaxios.formToJSON (thing) formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);类型定义中formToJSON的签名也明确支持两种输入见 index.d.ts而postForm/putForm/patchForm的 Promise 签名与普通请求方法一致见 index.d.ts。四、字段名路径记法Field-name path notation文档给出了一个可以直接被上述代码提交的示例表单form idhtmlForm input typetext namefoo value1 / input typetext namedeep.prop value2 / input typetext namedeep prop spaced value3 / input typetext namebaz value4 / input typetext namebaz value5 / select nameuser.age option valuevalue1Value 1/option option valuevalue2 selectedValue 2/option option valuevalue3Value 3/option /select input typesubmit valueSave / /form以 JSON 方式提交时它会被序列化为{ foo: 1, deep: { prop: 2 }, deep prop spaced: 3, baz: [4, 5], user: { age: value2 } }这段示例恰好覆盖了 lib/helpers/formDataToJSON.js 中parsePropPath的全部解析规则function parsePropPath(name) { // foo[x][y][z] - [foo, x, y, z] // foo.x.y.z - [foo, x, y, z] const path []; const pattern /[^.[\]]|\[([^.[\]]*)]/g; let match; while ((match pattern.exec(name)) ! null) { throwIfDepthExceeded(path.length); path.push(match[0] [] ? : match[1] || match[0]); } return path; }规则逐条对应文档中的 tip只有.和[...]会创建嵌套属性路径deep.prop被拆成[deep, prop]最终生成{deep: {prop: 2}}user.age同理生成{user: {age: value2}}空格、-、、*、等字符保留为字面字段名的一部分deep prop spaced不含.或括号整体就是顶层 key源码注释也明确说明user-name、user name这类 key 会被原样保留重复的 name 合并为数组两个baz输入框被合并为baz: [4, 5]。这一行为发生在formDataToJSON内部的buildPath函数中——当目标 key 已存在时若原值已是数组则concat否则包装成[旧值, 新值]见 lib/helpers/formDataToJSON.js[]语义foo[]中的[]段被解析为空字符串段buildPath里空段配合目标为数组时会取target.length作为下标实现数组追加。值得注意的还有源码中两个健壮性设计嵌套深度保护parsePropPath和buildPath都会调用throwIfDepthExceeded超过DEFAULT_FORM_DATA_MAX_DEPTH与toFormData共享的默认嵌套上限见 lib/helpers/toFormData.js 的导出会抛出AxiosError错误码ERR_FORM_DATA_DEPTH_EXCEEDED防止畸形字段名导致递归失控原型链污染防护buildPath遇到名为__proto__的段直接跳过不写入目标对象见 lib/helpers/formDataToJSON.js。formDataToJSON只遍历utils.forEachEntry中的实际条目不会触碰构造器原型链。相关行为在仓库中有独立测试覆盖可查阅 tests/unit/helpers/formDataToJSON.test.js 验证路径解析、重复 key、深度上限等用例。五、限制与注意事项文档明确声明的一条限制Sending Blobs/Files as JSON (base64) is not currently supported.即当前不支持把表单中的 Blob/文件字段以 base64 形式编码进 JSON。当表单包含input typefile时应走第一节的 multipart 路径postForm默认行为由FormData原生携带二进制文件而不是显式指定 JSON 内容类型。另外两点来自源码的适用前提直接提交form元素依赖HTMLFormElement与new FormData(formElement)属于浏览器能力在 Node 环境http/https 适配器中没有对应的 DOM 表单元素JSON 路径转换则同样可用Node 的FormData实现同样满足utils.isFormData显式 JSON 提交走的是JSON.stringify(formDataToJSON(data))因此最终 body 是字符串如需自定义序列化如字段重命名可覆盖transformRequest或在发送前用axios.formToJSON先取出普通对象自行处理。六、小结axios.postForm(url, formElement)直接提交页面上的 HTML 表单等价于post 默认Content-Type: multipart/form-datalib/core/Axios.jsHTMLFormElement到FormData的转换发生在默认transformRequest中lib/defaults/index.js显式设置Content-Type: application/json后FormData/HTML 表单会经formDataToJSON转为 JSON 字符串发送也可单独调用axios.formToJSON获取普通对象字段名只有.和[...]产生嵌套路径其余字符是字面名重复字段名自动合并为数组实现细节见 lib/helpers/formDataToJSON.js含深度上限与__proto__防护Blob/文件的 base64 JSON 编码目前不受支持文件字段请使用 multipart 表单路径。【免费下载链接】axiosPromise based HTTP client for the browser and node.js项目地址: https://gitcode.com/GitHub_Trending/ax/axios创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考