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 成对象。