fetch

用 XMLHttpRequest 来执行异步请求,虽然有用,却并不是最佳 api。它在设计上不符合职责分离原则,将输入、输出和用事件来跟踪的状态混杂在一个对象里(XMLHttpRequest 对象)。而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。
Fetch 的出现就是为了解决 XHR 的问题,其主要优点有:

  • 语法简洁,更加语义化
  • 基于标准 Promise 实现,支持 async/await
  • 同构方便,使用 isomorphic-fetch

Fetch API 旨在用来简化 HTTP 请求,它包含以下类和方法:

  • fetch 方法:用于发起 HTTP 请求
  • Request 类:用来描述请求
  • Response 类:用来表示响应
  • Headers 类:用来表示 HTTP 头部信息

这些类和方法在网上有着丰富的教程,在此不做赘述,可以查阅参考文献。

常见的坑

  • fetch 请求默认是不带 cookie 的,需要设置 fetch(url, {credentials: 'include'})
  • 服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。可以用response.statusresponse.ok 判断服务端是否返回错误。

fetch 发送 post 请求

$.ajax方法

首先我们看下 $.ajax post 数据的方法。

$.ajax({
  type: 'POST',
  url: '/video/v5video/item/add.htm',
  data: data,
  dataType: 'json'
})

chrome 中的请求信息:

这种情况下,服务器可以正常地解析 post 数据。

方法1:

fetch('/video/v5video/item/add.htm', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data),
  credentials: 'include'
})

chrome 中的请求信息:

可以看到,请求数据在 payload 中,在一些后台中(如webx),并不支持解析 payload 中的数据,此时将不能正常 post 数据。

方法2:

fetch('/video/v5video/item/add.htm', {
  method: 'POST',
  headers: {},
  body: setFormData(data),
  credentials: 'include'
});

function setFormData(data) {
  let formData = new FormData();
  for (let name in data) {
    formData.append(name, data[name]);
  }
  return formData;
}

chrome 中的请求信息:

存在着和方法一同样的问题。

方法3:

有没有什么方法可以让 fetch 发出和 $.ajax 一样的请求呢?答案是有的:

fetch('/video/v5video/item/add.htm', {
  method: 'POST',
  body: setUrlSearchParams(data),
  credentials: 'include'
});

function setUrlSearchParams(data) {
  let urlSearchParams = new URLSearchParams();
  for (let name in data) {
    urlSearchParams.append(name, data[name]);
  }
  return urlSearchParams;
}  

chrome 中的请求信息:

这样就达到了和 $.ajax 一样的效果了。

参考文献