JavaScript fetch 方式提交表单请求

最近在研究如何使用 fetch 方法发送表单请求,因为我们一般使用的时候fetch一般会将发送的数据处理成 JSON 字符串的格式进行发送,但是如果提交表单的话由于表单格式需要特殊处理,因为无法直接使用 fetch 进行发送,这里介绍一下如何处理可以使用 fetch 发送表单数据。

以一个表单作为示例,下图的HTTP请求将向本地发送一个表单提交的请求,请求表单内容包含

  • name : 张三
  • age : 23
  • sex : man
  • file : 简历.pdf
    在这里插入图片描述
    上图就是我们使用表单提交请求时,浏览器将我们的表单数据处理后的大致结果,首先会在内容类型(Cpontent-Type)设置为 multiparty/form-data 类型,然后设置了不同data之间的边界值,然后又边界开始对每个表单字段数据进行格式化处理。这样的格式直接调用 fetch 方法是得不到的,因为我们需要借助浏览器中的 FormData 对象进行处理:
form = document.createElement("form");
form.innerHTML = "<input name='name' value='张三' type='text'/>"
+"<input name='age' value='23' type='text'/>"
+"<input name='sex' type='male'/>"
+"<input name='file' type='file'/>"
+"<input name='submit' type='submit'/>";
form.onsubmit = function(){
    data = new FormData(this); // 将表单节点数据封装为 FormData 格式
    fetch("http://localhost:7001/form/submit",{
    	headers:{
    	// 注意这里不要设置 Content-Type 请求头,否则会导致错误
    	},
        method:"POST",
        Origin:window.location.protocol+"//"+window.location.host,
        // fetch 的 body 发送 data
        body:data
    }).then(res=>res.json()).then(json=>console.log(json));
    return false;
}
document.getElementsByClassName("body")[0].append(form);

上面的代码在执行后,会在页面最后增加一个表单元素,当点击提交的时候就会调用 onsubmit 中定义的方法发起 fetch 请求,并且将相应结果打印返回。

对于想要自定义的字段,也可以使用 FormData 对象中的方法进行追加,具体使用方式参考文档,下面为示例:

form = document.createElement("form");
form.innerHTML = "<input name='file' type='file'/><input name='submit' type='submit'/>";
form.onsubmit = function(){
    data = new FormData(this); // 将表单节点数据封装为 FormData 格式
    data.append("name","张三");
    data.append("age","23");
    data.append("sex","male");
    fetch("http://localhost:7001/form/submit",{
    	headers:{
    	// 注意这里不要设置 Content-Type 请求头,否则会导致错误
    	},
        method:"POST",
        Origin:window.location.protocol+"//"+window.location.host,
        // fetch 的 body 发送 data
        body:data
    }).then(res=>res.json()).then(json=>console.log(json));
    return false;
}
document.getElementsByClassName("body")[0].append(form);

如果我们想要自定义字段且上传文件,我们可以利用 <input type=‘file’>标签中的 files 属性,需要提交时向对应字段中上传文件

document.body.innerHTML = "<input id="form_file" type='file'/>";
form.onsubmit = function(){
    data = new FormData();
    // 添加 file 属性的表单字段
    data.append("file",document.getElementById("form_file").files[0]);
    fetch("http://localhost:7001/form/submit",{
    	headers:{
    	  // 注意这里不要设置 Content-Type 请求头,否则会导致错误
    	},
        method:"POST",
        Origin:window.location.protocol+"//"+window.location.host,
        // fetch 的 body 发送 data
        body:data
    }).then(res=>res.json()).then(json=>console.log(json));
    return false;
}
document.getElementsByClassName("body")[0].append(form);
关于 the request was rejected because no multipart boundary was found 异常

这是我在调试过程中遇到一个异常,通过 google 发现这个异常是由于未获取到表单数据边界导致的。
在这里插入图片描述
通过检查代码发现fetch之所以没有给我带上表单数据边界的原因是由于我手动定义了 Content-Type导致的,如下:

fetch("http://localhost:7001/form/submit",{
    	headers:{
    		"Content-Type":"multipart/form-data"
    	},
        method:"POST",
        Origin:window.location.protocol+"//"+window.location.host,
        // fetch 的 body 发送 data
        body:data
    }).then(res=>res.json()).then(json=>console.log(json));

有发现少了什么吗,当设置了 Content-Type后,对比之前的请求就会发现少了后面的表单数据边界部分的定义。这是因为由于我们手动设置了 Content-Type 之后,浏览器边不再会为我们自动设置Content-Type 了,发送的请求不是一个规范的表单请求,服务器无法正确解析而导致报错。
在这里插入图片描述
解决的方式也很简单,移除对 Content-Type的设置即可。

关于 Content-Type: application/x-www-form-urlencoded

在研究过程中发现了另外一种请求的数据类型,因为类型名称中带有 form所以一直以为和表单类型的请求有什么关系,经过一番研究之后发现这种类型的请求只是将请求地址中的数据移到了请求体中而已,如下:

POST http://localhost:7001/user?id=1&name=zhangsan&age=23

实际上和下面这种格式等价:

POST http://localhost:7001/user
Content-Type: application/x-www-form-urlencoded

id=1&name=zhangsan&age=23

这种格式有一个好处,就是请求头的长度实际上是有长度限制的,通过这种处理可以大大增加请求数据的长度。发起的 fetch 是这样的:

fetch("http://localhost:7001/user",{
    	headers:{
    		"Content-Type":"application/x-www-form-urlencoded"
    	},
        method:"POST",
        Origin:window.location.protocol+"//"+window.location.host,
        // fetch 的 body 发送 data
        body:"id=1&name=zhangsan&age=23"
    }).then(res=>res.json()).then(json=>console.log(json));

有感兴趣的童鞋可以深入研究下。

参考资料

form表单提交、ajax、fetch、formdata,以及跨域
fetch使用formdata数据格式发送请求
fetch 使用 form data 方式提交
HTTP请求中的form data和request payload的区别
React基于fetch的表单提交
FileUploadException1
FileUploadException2
FormData 对象的使用
使用 Fetch
jquery ajax三种方式异步提交表单

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值