用 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.status
或response.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
一样的效果了。