简介
Fetch API 提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,例如请求和响应。它还提供了一个全局 fetch()
方法,该方法提供了一种简单,合乎逻辑的方式来跨网络异步获取资源。
与ajax的区别
1.从 fetch()返回的 Promise 将不会拒绝HTTP错误状态, 即使响应是一个 HTTP 404 或 500。相反,它会正常解决 (其中ok状态设置为false), 并且仅在网络故障时或任何阻止请求完成时,它才会拒绝。
2.默认情况下, fetch在服务端不会发送或接收任何 cookies, 如果站点依赖于维护一个用户会话,则导致未经认证的请求(要发送 cookies,必须发送凭据头)。
说明:使用fetch模式,request header头是不会带cookies的,这样服务端就认为是不同的会话,解决方案:
设置fetch的options就好,我的如下:
const options= { method: "GET",mode: 'cors',credentials: 'include'};//same-origin
我因为用cors,所以credentials设置为include,如果不跨域,那么same-origin就行了。
特征检查
可以通过检查 Headers、Request、Response 或 fetch 在 window 或 worker 作用域中是否存在,来检查是否支持 Fetch API。
简单示例
fetch API中最常用的是fetch方法,该方法最简单的形式是,接受一个 URL 参数并返回以一个 promise 对象:
fetch("/data.json").then(function(res) {
// res instanceof Response == true.
if (res.ok) {
res.json().then(function(data) {
console.log(data.entries);
});
} else {
console.log("Looks like the response wasn't perfect, got status", res.status);
}
}, function(e) {
console.log("Fetch failed!", e);
});
如果提交的是一个post请求
fetch("http://www.example.org/submit.php", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "firstName=Nikhil&favColor=blue&password=easytoguess"
}).then(function(res) {
if (res.ok) {
alert("Perfect! Your settings are saved.");
} else if (res.status == 401) {
alert("Oops! You are not authorized.");
}
}, function(e) {
alert("Error submitting form!");
});
引入的接口
Fetch 引入了 3 个接口,分别是 Headers,Request 和 Response。
Headers
Headers 接口是一个简单的键值对:
var content = "Hello World";
var reqHeaders = new Headers();
reqHeaders.append("Content-Type", "text/plain"
reqHeaders.append("Content-Length", content.length.toString());
reqHeaders.append("X-Custom-Header", "ProcessThisImmediately");
也可以给构造函数传一个多维数组或 JS 字面量对象:
reqHeaders = new Headers({
"Content-Type": "text/plain",
"Content-Length": content.length.toString(),
"X-Custom-Header": "ProcessThisImmediately",
});
结合fetch使用:
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg', myInit);
fetch(myRequest).then(function(response) {
return response.blob();
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
});
Request
通过构造一个 Request 对象来获取网络资源,构造函数需要 URL、method 和 headers 参数,同时也可以提供请求体(body)、请求模式(mode)、credentials 和 cache hints 等参数。
var uploadReq = new Request("/uploadImage", {
method: "POST",
headers: {
"Content-Type": "image/png",
},
body: "image data"
});
mode 参数用来决定是否允许跨域请求,以及哪些 response 属性可读。可选的 mode 值为 "same-origin"、"no-cors"(默认)以及 "cors"。
same-origin
该模式很简单,如果一个请求是跨域的,那么将返回一个 error,这样确保所有的请求遵守同源策略。
no-cors
该模式允许来自 CDN 的脚本、其他域的图片和其他一些跨域资源,但是首先有个前提条件,就是请求的 method 只能是HEAD
、GET 或 POST。此外,如果 ServiceWorkers 拦截了这些请求,它不能随意添加或者修改除这些之外 Header 属性。第三,JS 不能访问 Response 对象中的任何属性,这确保了跨域时 ServiceWorkers 的安全和隐私信息泄漏问题。
cors
该模式通常用于跨域请求,用来从第三方提供的 API 获取数据。该模式遵守 CORS 协议,并只有有限的一些 Header 被暴露给 Response 对象,但是 body 是可读的。例如,获取一个 Flickr 最感兴趣的照片的清单:
var u = new URLSearchParams();
u.append('method', 'flickr.interestingness.getList');
u.append('api_key', '<insert api key here>');
u.append('format', 'json');
u.append('nojsoncallback', '1');
var apiCall = fetch('https://api.flickr.com/services/rest?' + u);
apiCall.then(function(response) {
return response.json().then(function(json) {
// photo is a list of photos.
return json.photos.photo;
});
}).then(function(photos) {
photos.forEach(function(photo) {
console.log(photo.title);
});
});
另外,credentials 属性决定了是否可以跨域访问 cookie 。该属性与 XHR 的
withCredentials 标志相同,但是只有三个值,分别是 omit(默认)、same-origin 和 include。
Response
Response 对象通常在 fetch() 的回调中获得,也可以通过 JS 构造,不过这通常只在 ServiceWorkers 中使用。
处理 body
在 Request 和 Response 对象中都可能有 body
属性,并且 body
可以是各种类型,比较复杂,所以前面我们故意先跳过它,在这里单独拿出来讲解。
body
可以是以下任何一种类型的实例:
ArrayBuffer
ArrayBufferView (Uint8Array and friends)
Blob/File
string
URLSearchParams
FormData —— 目前不被 Gecko 和 Blink 支持,Firefox 预计在版本 39 和 Fetch 的其他部分一起推出
Fetch和promise不足
1.不能中断,没有 abort、terminate、onTimeout 或 cancel 方法
2.缺少其它一些方法:always,progress,finally
3.没有 Deferred
4.没有获取状态方法:isRejected,isResolved