Fetch POST 接收不到数据,注意 content-type 的设置

Fetch POST 接收不到数据,注意 content-type 的设置

最近我们前端组在做一个简易的文档系统,使用redux+mongodb。其中抛弃了Ajax,起用了Fetch。

XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。

Fetch 的出现就是为了解决 XHR 的问题,Fetch API 是基于 Promise 设计。

刚开始用的时候发现个问题,POST数据发现后端获取不到,GET方式是没有问题的。如:

  fetch('/group/update', {
    method: 'post',
    body: JSON.stringify(params)
  })
    .then((response) => response.json())
    .then((json) => dispatch(fetchUpdateGroupName(json, index)))
    .catch((err) => (console.log('err:', err)))

以前一直用Jquery Ajax,很少情况需要设置Content-Type,而且看到有些博文介绍Fetch的时候说,Fetch()如果没有设置Content-Type,会自动获取。

后来还是被家优提醒,以下代码才是正确的设置:

  fetch('/group/update', {
    method: 'post',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(params)
  })
    .then((response) => response.json())
    .then((json) => dispatch(fetchUpdateGroupName(json, index)))
    .catch((err) => (console.log('err:', err)))

注意: Fetch 支持几种数据类型的传输,其中包含Blob, BLOB (binary large object),表示二进制大对象。其中有个只读属性,Blob.type(),此时的 Content-Type 应设置为此值。

这里顺便记录下POST常见的Content-Type:

application/x-www-form-urlencoded

浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。

POST http://www.123.com HTTP/1.1
Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

multipart/form-data

使用表单上传文件时,必须让 form 的 enctyped 等于这个值, 上传图片时,我们经常会看到下面这样

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="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

如果我们使用 new FormData()作为数据主体提交,也需要设置这种类型。

application/json

把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。但也有些服务端语言还没有支持这种方式,例如 php 就无法通过 $_POST 对象从上面的请求中获得内容。这时候,需要自己动手处理下:在请求头中 Content-Type 为 application/json 时,从 php://input 里获得原始输入流,再 json_decode 成对象。

参考: 四种常见的 POST 提交数据方式

0%