兼容性
IE11 及以下不行(万恶的 IE)
Fetch polyfill
引入下面这些 polyfill 后可以完美支持 IE8+ :
- 由于 IE8 是 ES3,需要引入 ES5 的 polyfill: es5-shim, es5-sham
- 引入 Promise 的 polyfill: es6-promise
- 引入 fetch 探测库:fetch-detector
- 引入 fetch 的 polyfill: fetch-ie8
- 可选:如果你还使用了 jsonp,引入 fetch-jsonp
- 可选:开启 Babel 的 runtime 模式,现在就使用 async/await
fetch()方法
fetch()方法用于发起获取资源的请求。
参数
第一个参数定义要获取的资源。这可能是:
- 一个 USVString 字符串,包含要获取资源的 URL。一些浏览器会接受 blob: 和 data: 作为 schemes.
- 一个 Request 对象。
第二个参数是可选的,是一个配置项对象,包括所有对请求的设置。
- method: 请求使用的方法,如 GET、POST。
- headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
- body: 请求的 body 信息:可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
- mode: 请求的模式,如 cors、 no-cors 或者 same-origin。
- credentials: 请求的 credentials,如 omit、same-origin 或者 include。为了在当前域名内自动发送 cookie , 必须提供这个选项, 从 Chrome 50 开始, 这个属性也可以接受 FederatedCredential 实例或是一个 PasswordCredential 实例。
- cache: 请求的 cache 模式: default 、 no-store 、 reload 、 no-cache 、 force-cache 或者 only-if-cached 。
- redirect: 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在 Chrome 中,Chrome 47 之前的默认值是 follow,从 Chrome 47 开始是 manual。
- referrer: 一个 USVString 可以是 no-referrer、client 或一个 URL。默认是 client。
- referrerPolicy: Specifies the value of the referer HTTP header. May be one of no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。
- integrity: 包括请求的 subresource integrity 值 ( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg');
fetch(myRequest,myInit).then(function(response) {
...
});
2
3
4
5
6
7
8
9
10
也可以传入同样的 init 对象到 Request 构造器,来实现同样的效果,如:
var myInit = { method: 'GET',
headers: {
'Content-Type': 'image/jpeg'
},
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg', myInit);
fetch(myRequest).then(function(response) {
...
});
2
3
4
5
6
7
8
9
10
11
返回值
它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。
当遇到网络错误时,fetch() 返回的 promise 会被 reject,并传回 TypeError,虽然这也可能因为权限或其它问题导致。
成功的 fetch() 检查不仅要包括 promise 被 resolve,还要包括 Response.ok 属性为 true。
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
2
3
4
5
6
7
注意,当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 Response.ok 设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。
Request 对象
得到 Request 对象
- 通过 Request.Request()构造函数创建一个 Request 对象,它的参数和 Fetch()方法的差不多,所以它能代替 Fetch()方法的 init 参数
- 一个 Request 对象也可能作为其它 API 的操作被返回,比如一个 service worker 的FetchEvent.request。
属性
Request 对象的属性都是只读的.
- Request.method 只读
- 包含请求的方法 (GET, POST, 等.)
var myRequest = new Request('flowers.jpg');
var myMethod = myRequest.method; // GET
2
- Request.url 只读
- 包含这个请求的 URL。
var myRequest = new Request('flowers.jpg');
var myURL = myRequest.url; // "http://mdn.github.io/fetch-examples/fetch-request/flowers.jpg"
2
- Request.headers 只读
- 包含请求相关的 Headers 对象。
var myRequest = new Request('flowers.jpg');
var myHeaders = myRequest.headers; // Headers {}
2
- Request.context 只读
- 包含请求的上下文(例如:audio, image, iframe, 等)
- Request.referrer 只读
- ?包含请求的来源 (例如:client)。
- Request.referrerPolicy 只读
- ?包含请求来源的策略 (例如:no-referrer)。
- Request.mode 只读
- 包含请求的模式 (例如: cors, no-cors, same-origin, navigate).
- Request.credentials 只读
- 包含请求的证书(例如: omit, same-origin,include).
- Request.redirect 只读
- 包含?如何处理重定向模式,它可能是一个 follow ,error 或者 manual。
- Request.integrity 只读
- 包含请求的子资源的完整性值 (例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=).
- Request.cache 只读
- 包含请求的缓存模式 (例如: default, reload, no-cache).
方法
- Request.clone()
- 创建当前 request 的副本。
- clone()TypeError 如果 Body 已经使用了响应,则抛出 a 。实际上,clone()存在的主要原因是允许 Body 对象的多次使用(当它们仅为一次使用时)。
- Request 实现 Body, 因此它也有 Body 的方法
Response 对象
得到 Response 对象
- 通过 Response.Response()构造函数创建一个 Response 对象
var myBlob = new Blob();
var init = { status: 200, statusText: 'SuperSmashingGreat!' };
var myResponse = new Response(myBlob, init);
2
3
- 一个 Request 对象也可能作为其它 API 的操作被返回,例如一个 service worker 的Fetchevent.respondWith,或者一个简单的 GlobalFetch.fetch()
属性
- Response.type 只读
- 包含 Response 的类型 (例如, basic, cors).
- Response.url 只读
- 包含 Response 的 URL.
- Response.useFinalURL
- 包含了一个布尔值来标示这是否是该 Response 的最终 URL.
- Response.status 只读
- 包含 Response 的状态码 (例如, 200 成功).
- Response.ok 只读
- 包含了一个布尔值来标示该 Response 成功(状态码 200-299) 还是失败.
- Response.redirected 只读
- 表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个
- Response.statusText 只读
- 包含了与该 Response 状态码一致的状态信息 (例如, OK 对应 200).
- Response.headers 只读
- 包含此 Response 所关联的 Headers 对象.
- Response 实现了 Body, 所以以下属性同样可用:
- Body.bodyUsed 只读
- 包含了一个布尔值来标示该 Response 是否读取过 Body.
方法
- Response.clone()
- 创建一个 Response 对象的克隆
- Response.error()
- 返回一个绑定了网络错误的新的 Response 对象
- Response.redirect()
- 用另一个 URL 创建一个新的 response.
- Response 实现了 Body, 因此它也有 Body 的方法
Headers 对象
Fetch API 的 Headers 接口允许您对 HTTP 请求和响应头执行各种操作。这些操作包括检索,设置,添加和删除。
- Headers.append()
- 给现有的 header 添加一个值, 或者添加一个未存在的 header 并赋值.
- Headers.delete()
- 从 Headers 对象中删除指定 header.
- Headers.entries()
- 以 迭代器 的形式返回 Headers 对象中所有的键值对.
- Headers.get()
- 从 Headers 对象中返回指定 header 的第一个值.
- Headers.getAll()
- 以数组的形式从 Headers 对象中返回指定 header 的全部值.
- Headers.has()
- 以布尔值的形式从 Headers 对象中返回是否存在指定的 header.
- Headers.keys()
- 以迭代器的形式返回 Headers 对象中所有存在的 header 名.
- Headers.set()
- 替换现有的 header 的值, 或者添加一个未存在的 header 并赋值.
- Headers.values()
- 以迭代器的形式返回 Headers 对象中所有存在的 header 的值.
let myHeaders = new Headers();
myHeaders.append('Content-Type', 'text/xml');
myHeaders.get('Content-Type');
// should return 'text/xml'
2
3
4
5
6
body 对象
Fetch API 中的 Body mixin 代表 代表响应/请求的正文,允许你声明其内容类型是什么以及应该如何处理。
正文由 Request 和 Response 实现 --- 这为这些对象提供了一个相关联的主体(字节流),一个已使用的标志(最初未设置)和一个 MIME 类型(最初为空字节序列)。
属性
- Body.bodyUsed 只读
- 包含一个指示 body 是否被读取过的 Boolean 值。
方法
- Body.arrayBuffer()
- 使用一个 buffer 数组来读取 Response 流中的数据,并将 bodyUsed 状态改为已使用。
- Body.blob()
- 使用一个 Blob 对象来读取 Response 流中的数据,并将 bodyUsed 状态改为已使用。
- Body.formData()
- 使用一个 FormData 对象来读取 Response 流中的数据,并将 bodyUsed 状态改为已使用。
response.formData().then(function(formdata) {
// do something with your formdata
});
2
3
- Body.json()
- 使用一个 JSON 对象来读取 Response 流中的数据,并将 bodyUsed 状态改为已使用。
fetch(`https://cdn.xgqfrms.xyz/json/badges.json`)
.then(response => response.json())
.then(data => {
console.log(`data = \n`, data);
});
2
3
4
5
- Body.text()
- 使用一个 USVString (文本) 对象来读取 Response 流中的数据,并将 bodyUsed 状态改为已使用。
Fetch 示例
postData('http://example.com/answer', { answer: 42 })
.then(data => console.log(data)) // JSON from `response.json()` call
.catch(error => console.error(error));
function postData(url, data) {
// Default options are marked with *
return fetch(url, {
body: JSON.stringify(data), // must match 'Content-Type' header
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, same-origin, *omit
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
},
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, cors, *same-origin
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer' // *client, no-referrer
}).then(response => response.json()); // parses response to JSON
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
发送带 cookie 的请求
fetch('https://example.com', {
credentials: 'include'
});
2
3
上传文件
var formData = new FormData();
var fileField = document.querySelector("input[type='file']");
formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);
fetch('https://example.com/profile/avatar', {
method: 'PUT',
body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));
2
3
4
5
6
7
8
9
10
11
12
13
上传多个文件
var formData = new FormData();
var photos = document.querySelector("input[type='file'][multiple]");
formData.append('title', 'My Vegas Vacation');
formData.append('photos', photos.files);
fetch('https://example.com/posts', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));
2
3
4
5
6
7
8
9
10
11
12
13
解决超时
const defaultOptions = {
headers: {
'Content-Type': 'application/json'
}
};
function request(url, options = {}) {
return new Promise((resolve, reject) => {
const headers = { ...defaultOptions.headers, ...options.headers };
let abortId;
let timeout = false;
if (options.timeout) {
abortId = setTimeout(() => {
timeout = true;
reject(new Error('timeout!'));
}, options.timeout || 6000);
}
fetch(url, { ...defaultOptions, ...options, headers })
.then(res => {
if (timeout) throw new Error('timeout!');
return res;
})
.then(checkStatus)
.then(parseJSON)
.then(res => {
clearTimeout(abortId);
resolve(res);
})
.catch(e => {
clearTimeout(abortId);
reject(e);
});
});
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
感言
其实写到这里,我已经放弃 Fetch 了,ajax 的已经很成熟的优点,例如超时,进度事件.....都已经支持,就为了 ajax 的一些缺点改为 Fetch,却损失了很多 ajax 的缺点,有点丢了西瓜捡芝麻,还是用 axios 吧