当前位置: 首页 > Web前端 > HTML5

面试官:你观察过chrome调试工具的requestbody吗?表单数据和请求负载有什么区别?

时间:2023-04-04 22:52:06 HTML5

前言这篇文章旨在记录自己的解惑过程。比如在chrome调试工具中,FormData和RequestPayload有什么区别?application/x-www-form-urlencoded和application/json有什么区别?我们在发展中应该如何选择?为什么后端有时会解析不到它发送的数据?在POST的跨域请求中,有没有办法不发送OPTIONS预检请求就发送数据?废话不多说,直奔主题。发现问题了,从两张截图入手,这两张截图是写这篇文章的初衷。微信文章打开,显示的是FormData。第二张图是掘金在打开文章时发起的请求。很奇怪,FormData和RequestPayload有什么区别?为什么都是POST请求,发送数据却有两种方式?我是那些不发现这种奇怪问题就无法入睡的人之一。我们在本地场景中重现一下,好好看看这两个东西。如果不想看中间的分析过程,可以点击Summary看Jay。该场景通过创建一个用于数据传输的XMLHttpRequest对象,并通过setRequestHeader()改变Content-Type,再现了前端和后端两个本地服务,最终我们在调试工具中完美再现了两种模式。本文中的所有示例代码都可以在此存储库中找到。想亲自试用的小伙伴可以点击查看详情示例地址。gitclone-bdemo/study-post-requesthttps://github.com/jsjzh/tiny-codes.gitRequestPayload如果想看到RequestPayload,需要设置请求头Content-Type:application/json,然后上传JSON.stringify序列化后发送的数据。可以看我的Origin:http://localhost.charlesproxy.com:3000,这是因为要用charles抓本地包,就得用这个做代理直接上传抓包。截图上半部分是一个完整的http请求,空行上方是请求头,空行下方是请求体。可以看到我们的请求体是一个json序列化后的字符串。下半部分注意JSON和JSONText选项卡,这是我们设置Content-Type:application/json后Charles自动带来的。后端收到http请求后,拦截空行后解析请求体。因为我们传的是Content-Type:application/json,后端知道请求体是json字符串,所以我们可以使用JSON.parse来解析。解析。发送的数据是{"name":"king","age":18,"isAdmain":true,"groups":[1,2,3],"address":"","foo":null,"bar":undefined,"extra":{"wechat":"kimimi_king","qq":454075623}}解析数据为{"name":"king","age":18,"isAdmain":true,"groups":[1,2,3],"address":"","foo":null,"extra":{"wechat":"kimimi_king","qq":454075623}}可以看到except除了bar:undefined,number、boolean、null等数据类型都传输正确。表单数据我们再来说说表单数据。我们需要设置Content-Type:application/x-www-form-urlencoded,然后在发送前通过qs.stringify将数据序列化。qs是qsnpmsource,是一个将数据转换为querystring的库。可以简单理解为可以将一个对象转化为类似get?如果直接发送下面的查询字段key=data&key2=data2,不做qs处理,方法会使用toString()将数据转成字符串。如果传输的是对象,会得到[objectObject]这里也直接贴出抓包的截图。上半部分是http请求。可以看到,当我们设置Content-Type:application/x-www-form-urlencoded时,请求体也放在了空行之后。后半部分,如果对比一下刚才的application/json,就能发现不一样了。JSON和JSONText的选项卡不见了,取而代之的是Form选项卡。后端收到http请求后,同样拦截空行后的请求体,使用qs.parse解析。发送的数据是{"name":"king","age":18,"isAdmain":true,"groups":[1,2,3],"address":"","foo":null,"bar":undefined,"extra":{"wechat":"kimimi_king","qq":454075623}}解析数据为{"name":"king","age":"18","isAdmain":"true","groups":["1","2","3"],"address":"","foo":"","extra":{"wechat":"kimimi_king","qq":"454075623"}}与Content-Type:application/json对比后可以看出,不仅number和boolean的数据类型丢失了,而且foo:null也被转换成了foo:""。交换序列化方式刚才我们尝试了正确的Content-Type对应正确的序列化方式application/json+JSON.stringifyapplication/x-www-form-urlencoded+qs.stringify但实际上我们观察到了实际的http请求每个Content-Type在一个空行之后传输数据,当然我们也可以交换他们的序列化方式。application/json+qs.stringify这里直接得出结论。我们设置application/json,但是使用qs.stringify来序列化。结果就是无法解析chrome调试工具的RequestPayload,所以无法格式化数据。charles工具的JSON和JSONText不能解析最重要的东西。如果后端读取到的Content-Type为application/json,它将使用JSON.parse来解析数据。当然我们可以手动使用qs.parse来解析后端,但是为什么要自己给Bury呢?application/x-www-form-urlencoded+JSON.stringify一样,使用Content-Type,序列化方式不正确,不仅chrome和charles无法解析,后端也会有疑惑,更重要的是会给自己埋坑.总结一下,没错,我只是想总结一下前面说的,现在总结一下FormData和RequestPayload,因为请求的content-type不一样,解析请求体后的呈现方式也不一样。content-type设置为Application/json或application/x-www-urlencoded在http请求中,除了Header外没有区别,requestbody放在一个空行之后。开发中应该如何选择Content-Type?建议如果项目没有特殊要求,使用application/json,原因如下。原生的JSON.stringify和JSON.parse不好吗?qs在前端有很多实现,比如qs和query-string,node自带的querystringx-www-form-urlencoded需要使用配套的qs.stringify。后端解析数据后,会丢失数据类型,比如number、boolean、null不同的框架对qs.parse的实现方式不同。项目初期可能会有前后端对齐解析的操作。前端qs仓库默认只能处理5层对象,默认只能解析1000个参数(当然这两个配置都可以修改)举个例子{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"name":"king"}}}}}}}}因为对象嵌套的层数太深,解析后变成如下{"a":{"b":{"c":{"d":{"e":{"[f][g][name]":"king"}}}当然,使用application/json后会有一些区别。配置完headerContent-Type:application/json不是简单的请求,会发起Optionspreflight请求后端需要同步配置Access-Control-Request-Headers:Content-Type,让前端配置Content-Typeheader。我正在整理这方面的内容,大家可以稍微期待一下。不知道这篇文章是否给你带来了一些帮助。如果是这样,那是我的荣幸。遇到问题,不妨深挖一下。一点,就像这次的FormData和RequestPayload一样,我们深入到http请求层面,可以发现两者其实并没有什么区别。它是浏览器对http协议的一种封装,Content-Type的正确使用是我们与后端联调的一种约定,也是一种规范。当然我们可以随意设置Content-Type,但是这样就需要和后台进行不必要的联调,也不方便后续的理解和维护,所以还是简单点吧,有的框架会根据Content-TypeRequestbody的值,毛已经这么少了,我们不想强行增加游戏难度。页脚代码就是生命,我喜欢它。技术日新月异,思想永远在线,前端长。下期我们不见不散---胯下三人组,我来了gayhub@jsjzh欢迎大家来和我一起玩。欢迎朋友直接加我,拉你进群一起做事,记得备注看文章的地方。ps:如果图片失效,可以加我微信:kimimi_king