乐趣区

前后端联调之Form Data与Request Payload,你真的了解吗?

前言
做过前后端联调的小伙伴,可能有时会遇到一些问题。例如,我明明传递数据给后端了,后端为什么说没收到呢?这时候可能就会就会有小伙伴陷入迷茫,本文从 chrome-dev-tools(F12 调试器)中看到的 FormData 与 RequestBody,给小伙伴们提供一种可能的思路。也给小伙伴们提供一些问题的探究方法。
简介
什么是 FormData?什么是 RequestPayload?不解释,直接上图:

区别?
因为这里触及了我的知识盲区,所以有了本文。这个答案是我在 stackoverflow 上得到的。首先还是贴问题,贴答案。
What’s the difference between“Request Payload”vs“Form Data”as seen in Chrome dev tools Network tab。中文翻译:chrome 开发者工具中的 Request Payload 与 Form Data 有什么区别?
高票回答:

The Request Payload – or to be more precise: payload body of a HTTP Request – is the data normally send by a POST or PUT Request. It’s the part after the headers and the CRLF of a HTTP Request.
A request with Content-Type: application/json may look like this:
POST /some-path HTTP/1.1
Content-Type: application/json

{“foo” : “bar”, “name” : “John”}

If you submit this per AJAX the browser simply shows you what it is submitting as payload body. That’s all it can do because it has no idea where the data is coming from.
If you submit a HTML-Form with method=”POST” and Content-Type: application/x-www-form-urlencoded or Content-Type: multipart/form-data your request may look like this:
POST /some-path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar&name=John
In this case the form-data is the request payload. Here the Browser knows more: it knows that bar is the value of the input-field foo of the submitted form. And that’s what it is showing to you.
So, they differ in the Content-Type but not in the way data is submitted. In both cases the data is in the message-body. And Chrome distinguishes how the data is presented to you in the Developer Tools.

翻译过来是说:Request Payload 更准确的说是 http request 的 payload body。一般用在数据通过 POST 请求或者 PUT 请求。它是 HTTP 请求中空行的后面那部分。(PS: 这里涉及一个 http 常被问到的问题,http 请求由哪几部分组成,一般是请求行,请求头,空行,请求体。payload body 应该是对应请求体。)
一个请求伴随着 header 设置为 Content-Type: application/json 时候,看起来可能像这样:
POST /some-path HTTP/1.1
Content-Type: application/json

{“foo” : “bar”, “name” : “John”}
如果你正常请求一个 ajax。浏览器会简单的将你提交的内容作为 payload 展示出来,这就是它所能做的,因为它不知道数据来自哪里。
如果你提交了一个 html 表单并且配置上了 method=”post”,并且设置了 Content-Type: application/x-www-form-urlencoded 或者 Content-Type: multipart/form-data。那么你的请求可能长这个样:
POST /some-path HTTP/1.1
Content-Type: application/x-www-form-urlencoded

foo=bar&name=John
这里的 form-data 就是 request payload。在这里,浏览器知道更多:它知道 bar 是提交表单的输入字段 foo 的值。这就是它向你展示的。
所以区别就是,他们只是因为 Content-Type 设置的不同,并不是数据提交方式的不同,这两种提交都会将数据放在 message-body 中。但是 chrome 浏览器的开发者工具会根据这个 ContentType 区分显示方式。
细节
好了,到这里我们知道了,其实都是放到了 payload 中。那么具体有什么区别呢?为什么有时候后端拿不到值呢?这就不得不说对 payload 的解析方式了。我们以几个 chrome 下的测试案例,来理一理这个逻辑。
传统的 Form 表单提交
场景构造
<form action=”/” method=”POST”>
<input name=”name” type=”text”>
<input name=”password” type=”text”>
<button> 提交 </button>
</form>
如果我这里点击提交按钮,就会触发浏览器的提交功能,那结果是什么样呢?

注意点
可以看到 Content-Type 为 application/x-www-form-urlencoded。值得形式是以 key1=value1&key2=value2 的形式提交的。
传统的 ajax 提交
场景构造
function submit2() {
var xhr = new XMLHttpRequest();
xhr.timeout = 3000;
var obj = {a: 1, b: 2};
xhr.open(‘POST’, ‘/’);
xhr.send(obj);
}
首先我们构造一个简单的函数,然后触发它。通过 chrome 反馈来看:

注意点
1. 默认的 Content-Type 为 text/plain。2.Request Payload 会对非字符串做字符串转换。3. 通过 xhr.send(JSON.stringify(obj)); 可修正要发的内容
axios 方式提交
场景构造
由于 axios 已经是 vue、react 的准标配请求方式了,所以这里探究一下它。首先我门看 axios 的文档,当 post 提交时候可以传递什么类型参数:

注意这个类型,我们分别构造两个场景。对应它。
function submit3() {
var sence1 = ‘name=123&val=456’;
var sence2 = {name: 123, val: 456};
axios.post(‘/’, sence1)
}
分别传递字符串与对象,提交 post 请求,然后观察结果:
场景 1——传递字符串时候的结果:
场景 2——传递对象的结果:
注意点
1. 当我们传递字符串的时候,Content-Type 自动转为 xxx-form-xxx 的形式。当为对象的时候,自动转化为 xxx/json。2. 字符串的时候以 key1=val1&key2=val2 的形式体现,对象以 JSON 字符串形式体现。
总结
探索了这么多种情况之后,那么我们回顾一下:
Content-Type 的差异
1. 传统的 ajax 请求时候,Content-Type 默认为 ” 文本 ” 类型。2. 传统的 form 提交的时候,Content-Type 默认为 ”Form” 类型。3.axios 传递字符串的时候,Content-Type 默认为 ”Form” 类型。4.axios 传递对象的时候,Content-Type 默认为 ”JSON” 类型
Content-Type 的值,Form 与非 Form 时,payload 的区别。
1. 都只支持字符串类型 (以上探究的几种情况)2.Form 需要传递的格式为 key1=value1&key2=value2, 类似 GET 请求的 QueryString 格式 3. 非 Form 一般为 JSON.stringify(formDataObject) 形式
后端取不到值?
无论何种形式传递,后端解析表单信息的时候,会考虑 Content-Type。如果是 JSON 字符串的话,后端解析 payload 的内容时候,肯定要去解析 JSON 啦。如果是 key1=value1&key2=value2 的形式,则需要去分割字符串。
当然这些事情一般后端使用的框架会去处理,但是框架给后端提供取值接口有可能是不同的,所以前端的小伙伴在处理请求问题时,一定要跟后端小伙伴商量好,是用 JSON 还是 FormData 哈。
后记
本来只是小小的一个问题,仔细研究起来发现挺多细节。今天就花时间整理了一下,希望能给大家一些帮助。码字不容易,如果感到这篇文章对你有用。点个赞,收个藏呗。

退出移动版