乐趣区

关于前端:面试官观察过-chrome-调试工具的请求体么Form-Data-和-Request-Payload-有什么区别

前言

这篇文章旨在记录本人解惑过程,比方

  1. 在 chrome 调试工具中,Form DataRequest Payload 有什么区别?
  2. application/x-www-form-urlencodedapplication/json 有什么区别?开发中咱们应该怎么抉择?
  3. 为什么后端有时会无奈解析本人发送的数据?
  4. POST 的跨域申请中,有方法不发送 OPTIONS 预检申请也能发送数据的办法么?

话不多说,间接进入主题。

发现问题,从两个截图开始

这两个截图就是写这篇文章的初衷,微信文章在关上的时候是显示的 Form Data,第二张图是掘金在关上文章发动的申请,过后看到就特奇怪,Form DataRequest Payload 这俩货有啥区别?为啥都是 POST 申请,但却有两种发送数据的形式?

我这个人就是属于碰到这种奇怪的问题不把他搞清楚就睡不了觉的人,咱们间接在本地场景重现,好好看看这俩货。

如果不想看两头的剖析过程,能够间接点击 总结 看杰伦。

场景重现

本地起两个服务,前端和后端,通过创立 XMLHttpRequest 对象来进行数据传输,并通过 setRequestHeader() 来扭转 Content-Type,最终咱们在调试工具中完满重现了两种模式。

文章里的示例代码都能够从这个仓库里找到,心愿本人亲自尝试的小伙伴能够点击查看详情 示例地址。

git clone -b demo/study-post-request https://github.com/jsjzh/tiny-codes.git

Request Payload

如果心愿看到 Request Payload,须要设置申请头部 Content-Type: application/json,再将数据通过 JSON.stringify 序列化后发送。

大家能够看到我这里的 Origin: http://localhost.charlesproxy.com:3000,这是因为要用 charles 抓本地包,得用这做一层代理

间接上抓包的截图

上半局部就是一个残缺的 http 申请,空行下面为申请头,空行上面是申请体,能够看到咱们的申请体就是一个 json 序列化后的字符串。

下半局部,留神 JSONJSON Text 两个 tab,这个是咱们设置了 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}
}

能够看到除了 bar: undefined 之外,numberbooleannull,数据类型都被正确的传输了。

Form Data

再来说说 Form Data,咱们须要设置 Content-Type: application/x-www-form-urlencoded,再将数据通过 qs.stringify 序列化后再发送。

qs 即为 qs npm source,是一个将数据 querystring 化的库

能够简略了解成他能够把一个对象转换成相似 get 申请中 ? 前面的查问字段 key=data&key2=data2

如果不通过 qs 解决间接发送,办法会应用 toString() 来将数据转为字符串,如果传输的是对象,你会失去 [object Object]

这里也间接贴出抓包的截图

上半局部就是 http 申请,能够看到当咱们设置 Content-Type: application/x-www-form-urlencoded 申请体也是放在了空行之后。

下半局部,比照方才的 application/json 就能发现不一样的中央了,JSONJSON Text 的 tab 不见了,取而代之的是 Form tab。

后端接到 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 比照,咱们能够看到,不仅 numberboolean 的数据类型失落,并且 foo: null 还被转换成了 foo: ""

替换序列化形式

方才咱们尝试了正确的 Content-Type 对应正确的序列化形式

application/json + JSON.stringify

application/x-www-form-urlencoded + qs.stringify

但其实咱们察看到理论的 http 申请,这两个 Content-Type 都是将数据放在空行后传输,所以咱们当然也能够替换他们的序列化形式。

application/json + qs.stringify

这里间接就说论断,咱们设置了 application/json,但应用 qs.stringify 序列化,后果就是

  1. chrome 调试工具的 Request Payload 无奈解析,遂无奈格式化数据
  2. charles 工具的 JSONJSON Text 无奈解析
  3. 最重要的,后端若是读取了 Content-Typeapplication/json,就会应用 JSON.parse 来解析数据

在后端咱们当然能够手动用 qs.parse 来进行解析,然而咱们为什么要给本人埋坑?

application/x-www-form-urlencoded + JSON.stringify

同理,应用了 Content-Type 和不正确的序列化形式,不仅 chrome 和 charles 无奈解析,后端也会有纳闷,更重要的是会给本人埋坑。

总结

诶,没错,我就想皮一下

后面说了这么多,当初来总结一下

  1. Form DataRequest Payload 就是因为申请的 Content-Type 不同,而不同的解析申请体后的出现形式
  2. Content-Type 设置成 application/json 还是 application/x-www-urlencoded 在 http 申请中,除了 Header 以外并无区别,都是将申请体放在空行后

那咱们在开发中应该如何抉择 Content-Type?倡议如果不是我的项目有特地要求,都应用 application/json,起因有以下几点

  1. 原生自带的 JSON.stringifyJSON.parse 不香么?qs 在前端就有很多实现,比方 qsquery-string,还有 node 自带的 querystring
  2. x-www-form-urlencoded 须要应用配套 qs.stringify 后端解析数据后会失落数据类型 ,比方 numberbooleannull
  3. 不同的框架对于 qs.parse 的实现形式不同,在我的项目刚开始对接时可能会有前后端对齐解析形式的操作
  4. 前端的 qs 仓库默认只能解决 5 层对象,默认只能解析 1000 个参数(当然,这两个配置都能够批改)举一个例子
{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": {
            "f": {"g": { "name": "king"}
            }
          }
        }
      }
    }
  }
}

因为对象嵌套的层数太深,解析后就成了如下

{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": {"[f][g][name]": "king"
          }
        }
      }
    }
  }
}

当然,应用了 application/json 之后会有些不一样

  1. 配置头部 Content-Type: application/json 之后就不是简略申请,会发动一个 Options 预检申请
  2. 后端须要同步配置 Access-Control-Request-Headers: Content-Type,容许前端配置 Content-Type 头部

当然,再说下去就是 CORS 的知识点了,这方面也有很多内容能够掰开细说,我也正在整顿这方面的内容,能够小小的期待一下。

后语

不晓得这篇文章是否给你带来了一些帮忙,如果有的话是我的荣幸,在平时碰到问题的时候无妨能够挖的深一点,就像这次的 Form DataRequest Payload,当咱们开掘到 http 申请层面就能发现两者其实并无区别,就是浏览器对于 http 协定的一种封装,而正确的应用 Content-Type 就是咱们和后端联调的一个约定,也是一个标准。

咱们当然能够随便设置 Content-Type,然而这就须要和后端进行非必要联调,并且也不不便后续了解保护,所以咱们能简略就简略一些,有些框架会主动依据 Content-Type 的值来解析申请体,头发曾经这么少了,咱们就不要强行减少游戏难度了。

页脚

代码即人生,我甘之如饴。

技术一直在变
头脑始终在线
前端路漫漫
咱们下期见

by — 裤裆三重奏

我在这里 gayhub@jsjzh 欢送大家来找我玩儿。

欢送小伙伴们间接加我,拉你进群一起搞事件,记得备注一下你是从哪里看到文章的。

ps: 如果图片生效,能够加我 wechat: kimimi_king

退出移动版