从jQuery.ajax到fetch,你还差一本HTTP权威指南

作为前端出身的,码农,没有深入了解过HTTP,一直以来靠抹平XMLHttpRequest种种细节的jq发送http请求,直到有一天我想用fetch的时候...遇到了许多莫名的问题。这些问题就好象是你想学vue的时,折腾半天webpack;想写ES6时,折腾半天babel配置;想学node时,不知无从下手。我想这种情况,或许只有非CS出身前端出身的程序员才会理解吧。

有一天我发送了这么一个请求(不要问我为什么查询用POST方法)

let _this = this;
let data = {
  pageIndex: 1,
  pageSize: 20,
  key: getParam('key'),
  cid: getParam('cid'),
  sortKey:'new'
};
$.ajax({
  type: 'POST',
  url: `${api}/search/search.do`,
  data: data,
  success(json){
    if (json.code === 1000) {
      _this.items = json.data;
    }
  }
})

一切正常...然后我改成fetch发送吧。

fetch(`${api}/search/search.do`, {
  method: "POST",
  body: JSON.stringify(data)
})
.then(response => {
  if (response.ok === true) {
    return response.json();
  }
})
.then(json => {
  if (json.code === 1000) {
    _this.items = json.data;
  }
})
.catch(err => {
  console.log('getJson error' + err)
})

是的...我以为全世界大多数请求都是用json沟通的。
于是我仔细对比了两次请求的不同。

从jQuery.ajax到fetch,你还差一本HTTP权威指南_第1张图片
fetch

从jQuery.ajax到fetch,你还差一本HTTP权威指南_第2张图片
jquery

二者的 Content-Type是不同的,我们可以看到 fetch请求,因为我没有在请求头里定义类型,所以当前是 text/plain,即普通文本类型。为什么jquery发出的却是 application/x-www-form-urlencoded呢?
...那当然是因为jq的ajax方法自带默认配置啊...(其实也可能是因为 XMLHttpRequest对象发送POST请求有默认的 Content-Type配置,已确认并未配置。)

从jQuery.ajax到fetch,你还差一本HTTP权威指南_第3张图片
jquery源码

所以application/x-www-form-urlencoded到底是一种什么样的类型呢?

从jQuery.ajax到fetch,你还差一本HTTP权威指南_第4张图片
jquery发送的数据

可以看到我们发送的数据挺好的...

从jQuery.ajax到fetch,你还差一本HTTP权威指南_第5张图片
fetch发送的数据

但是对比点击 view source后的结果可以看出,fetch发出的是json格式,而jq发出的请求是这样的

jq请求 view source

再仔细看它的类型 application/x-www-form-urlencoded,前面先不管... urlencoded,我们知道js提供 encodeURI方法,用于将完整的URI转义。所以这一串数据,应该是 encodeURI('pageIndex=1&pageSize=20&key=女装&cid=1&sortKey=new')返回的内容。
回到我们最初的目的。用fetch做同样的事情...首先我们要把对象遍历成 key=value的形式。
我们写个转换的函数(未考虑深层对象的情况)

function getUriEncodeParam(data) {
  let newArr = Object.keys(data);
  let param = '';
  newArr.forEach(function (item, idx) {
    if (idx === 0) {
      param += item + '=' + data[item];
    } else {
      param += '&' + item + '=' + data[item];
    }
  });
  return encodeURI(param);
}

//fetch
fetch(`${api}/search/search.do`, {
  method: "POST",
  headers:{
    'content-type':'application/x-www-form-urlencoded; charset=UTF-8'
  },
  body: getUriEncodeParam(data)
})

成功响应,请求头部分也按照预期,响应的数据也正常了。
同时也自惭形秽用jquery发请求那么多年(好像也有2年了...)似乎只关注url,data,回调但很少注意到请求头的一些东西...
以下提几个常用的POST数据类型。

  • application/x-www-form-urlencoded
    浏览器原生的
    表单,当 method属性值为 post 时, enctype属性可以定义提交给服务器的媒体类型,application/x-www-form-urlencoded是默认值。可取的值还有multipart/form-datatext/plain(HTML5)
  • multipart/form-data
    用于发送文件等二进制数据。
从jQuery.ajax到fetch,你还差一本HTTP权威指南_第6张图片
multipart/form-data类型的请求
  • application/json
  • text/xml

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

你可能感兴趣的:(从jQuery.ajax到fetch,你还差一本HTTP权威指南)