导读
Fetch 是 web 异步通信的未来。从chrome42,Firefox39,Opera29,EdgeHTML14(并非Edge版本)起,fetch就已经被支持了。其中chrome42~45版本,fetch对中文支持有问题,建议从chrome46起使用fetch。
Fetch
先过一遍Fetch原生支持率。
可见要想在IE8/9/10/11中使用fetch还是有些犯难的,毕竟它连 Promise 都不支持,更别说fetch了。别急,这里有polyfill(垫片)。
- es5 的 polyfill — es5-shim, es5-sham
- Promise 的 polyfill — es6-promise
- fetch 的 polyfill — fetch-ie8
由于IE8基于ES3,IE9支持大部分ES5,IE11支持少量ES5,其中只有IE10对ES5支持比较完整。因此IE8+浏览器,建议依次装载上述垫片。
尝试一个fetch
先来看一个简单的fetch。
1 | var word = '123', |
fetch执行后返回一个 Promise
对象,执行成功后,成功打印出 Response
对象。
该fetch可以在任何域名的网站直接运行,且能正常返回百度搜索的建议词条。以下是常规输入时的是界面截图:
以下是刚才fetch到的部分数据。其中 key name 为 s
的字段的 value
就是以上的建议词条(由于有高亮词条 12306,最后一条数据 12366 被顶下去了,故上面截图上看不到)
看完例子过后,就要动真格了,下面就来扒下 Fetch。
Promise特性
fetch方法返回一个 Promise
对象,根据 Promise Api 的特性,fetch可以方便地使用 then
方法将各个处理逻辑串起来,使用 Promise.resolve()
或 Promise.reject()
方法将分别返会 肯定结果的Promise 或 否定结果的Promise,从而调用下一个 then
或者 catch
;一但 then
中的语句出现错误,也将跳到 catch
中。
若对Promise有疑问, 请阅读 Promises官方文档。
情景1:同域下请求
我们在 https://sp0.baidu.com 域名的网页控制台运行以下代码。
1 | var word = '123', |
运行截图如下:
情景2:非同域请求(跨域请求)
我们在非 https://sp0.baidu.com 域名的网页控制台再次运行以上代码(别忘了给fetch的第二参数传递 {mode: "no-cors"}
)。
运行截图如下:
由于第一次进入 then 分支后,返回了否定结果的 Promise.reject 对象。因此代码进入到 catch 分支,抛出了错误。此时,上述 response.type
为 opaque
。
Response Type
一个fetch请求的响应类型(response.type)为如下三种之一:
- basic
- cors
- opaque
如上情景1,同域下,响应类型为 “basic”;
如上情景2中,跨域下,服务器没有返回 CORS
响应头,响应类型为 “opaque”。此时我们几乎不能查看任何有价值的信息,比如不能查看response,status,url等等。
同样是跨域下,如果服务器返回了CORS响应头,那么响应类型将为 “cors”。此时响应头中除 Cache-Control ,Content-Language ,Content-Type ,Expores ,Last-Modified 和 Progma 之外的字段都不可见。
注意:无论是同域还是跨域,以上 fetch 请求都到达了服务器。
mode
fetch可以设置不同的模式使得请求有效;模式可在fetch方法的第二个参数对象中定义。
1 | fetch(url, {mode: 'cors'}); |
可定义的模式如下:
- same-origin: 表示同域下可请求成功;反之,浏览器将拒绝发送本次fetch,同时抛出错误 “TypeError: Failed to fetch(…)”
- cors: 表示同域和带有CORS响应头的跨域下可请求成功,其他请求将被拒绝
- cors-with-forced-preflight: 表示在发出请求前,将执行preflight检查
- no-cors: 常用于跨域请求不带CORS响应头场景,此时响应类型为 “opaque”
除此之外, 还有两种不太常用的mode类型,分别是 navigate,websocket,它们是 HTML标准 中特殊的值,这里不做详细介绍。
header
fetch 获取 HTTP 响应头非常容易,如下所示:
1 | fetch(url).then(function(response) { |
设置 HTTP 请求头也一样简单:
1 | var headers = new Headers(); |
Header 的内容也可以被检索的:
1 | var headers = new Headers({ |
post
在fetch中发送post请求,同样可以在fetch方法的第二个参数对象中设置。
代码如下:
1 | var headers = new Headers(); |
credentials
跨域请求中需要带有cookie时,可在fetch方法的第二个参数对象中添加 credentials
属性,并将值设置为 include。
1 | fetch(url, { |
除此之外,credentials 还可以取以下值:
- omit: 缺省值,默认为该值
- same-origin: 同源,表示同域请求才发送cookie
catch
同 XMLHttpRequest 一样,无论服务器返回什么样的状态码(chrome中除407之外的其他状态码),它们都不会进入到错误捕获里。也就是说,此时,XMLHttpRequest 实例不会触发 onerror
事件回调,fetch 不会触发 reject。通常只在网络出现问题时或者 ERR_CONNECTION_RESET
时,它们才会进入到相应的错误捕获里(其中,请求返回状态码为407时,chrome浏览器会触发 onerror 或者 reject 掉 fetch)。
cache
cache 表示如何处理缓存,遵守 HTTP 规范,拥有如下几种值:
- default: 表示fetch请求之前将检查下http的缓存
- no-store: 表示fetch请求将完全忽略http缓存的存在。这意味着请求之前将不再检查下http的缓存,拿到响应后,它也不会更新http缓存
- no-cache: 如果存在缓存,那么fetch将发送一个条件查询request和一个正常的request,拿到响应后,它会更新http缓存
- reload: 表示fetch请求之前将忽略http缓存的存在,但是请求拿到响应后,它将主动更新http缓存
- force-cache: 表示fetch请求不顾一切的依赖缓存,即使缓存过期了,它依然从缓存中读取。除非没有任何缓存,那么它将发送一个正常的request
- only-if-cached: 表示fetch请求不顾一切的依赖缓存,即使缓存过期了,它依然从缓存中读取。如果没有缓存,它将抛出网络错误(该设置只在mode为”same-origin”时有效)
如果fetch请求的header里包含 If-Modified-Since
,If-None-Match
,If-Unmodified-Since
,If-Match
,或者 If-Range
之一,且cache的值为 default
,那么fetch将自动把 cache的值设置为 no-store
。
【未完】