前言
今天写业务代码时遇到一个错误,这是一个包含文件上传的修改接口,在请求的时候,接口状态码报500,之后就跟后端同学说,服务器错误,检查一下代码吧。后端同学看了遍代码没发现有什么问题?打断点调试也走不到接口中去。在接口文档中调试的时候发现,新增接口的请求体中 content-type 为 multipart/form-data,修改接口围为content-type 为 application/x-www-form-urlencoded,但是通过浏览器调用时都是multipart/form-data类型。
请教了好几个小伙伴都没发现是什么问题,最后发现通过对比上传的数据后发现,如果不上传文件的话,以formData表单提交的数据会以 application/x-www-form-urlencoded 的方式发送,加上文件的话是以 multipart/form-data 方式提交。在文档中调试接口时,文档会判断提交的数据中有没有文件从而选取不同的上传方式。项目中的话由于配置的axios使以formData提交的数据的方式均为multipart/form-data,没有更改文件时,file这个键的值为null formData.append('file',null)
导致了调用接口报500。
正常来说虽然有控制但是是允许这样提交数据的。但是为了避免出现类似这样容易让人摸不着头脑的错误,再来复习以下这几种数据提交方式吧。
三种常见的POST 请求数据提交方式:
- application/json
- application/x-www-form-urlencoded
- multipart/form-data
application/json
application/json 这个 Content-Type 作为响应头是最常用到的方式。它用来告诉服务端消息主体是序列化后的 JSON 字符串。它具有以下几个特点:
- 方便的提交复杂的结构化数据
- 现代化浏览器都中的开发者工具会以json格式展示数据,便于开发调试
application/x-www-form-urlencoded
application/x-www-form-urlencoded 是以formData 方式提交数据的其中一中,浏览器的原生 form 表单,最终就是以这种方式提交数据的。他的特点有:
- 参数用符号
&
间隔(example:key1=val1&key2=val2)
multipart/form-data
使用表单上传文件时,需要用到,multipart/form-data。下面的例子展示了如何使用form表单提交一个formdata请求。
<form id="form">
First name: <input type="text" name="firstName" value="Mickey"><br>
Last name: <input type="text" name="lastName" value="Mouse"><br>
<input type="file" name="file"><br>
</form>
<button onclick="submitForm()">提交</button>
<script>
function submitForm() {
var formElement = document.getElementById("form");
var xhr = new XMLHttpRequest();
xhr.open("POST", "/task/testFile");
xhr.send(new FormData(formElement));
}
</script>
发起文件上传请求后可以看到请求体如下:
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="text"
title
------WebKitFormBoundaryrGKCBY7qhFd3TrwA
Content-Disposition: form-data; name="file"; filename="dog.png"
Content-Type: image/png
PNG ... content of dog.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
使用分隔符分割不同的字段
指明了分割符是什么
消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 –boundary 开始,紧接着内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)