Fetch API 提供了一个获取资源的接口(包括跨网络)。任何使用过 XMLHttpRequest 的人都会熟悉它,新的 API 提供了更强大和更灵活的功能集。Fetch 提供了对 Request 和 Response (以及其他与网络请求有关的)对象的通用定义。使之今后可以被使用到更多地应用场景中:无论是 service workers、Cache API、又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式。
在新的 ES7 提案中新添加了 fetch() 方法,fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。
当遇到网络错误时,fetch() 返回的 promise 会被 reject,并传回 TypeError,虽然这也可能因为权限或其它问题导致。成功的 fetch() 检查不仅要包括 promise 被 resolve,还要包括 Response.ok 属性为 true。HTTP 404 状态并不被认为是网络错误。
此功能某些浏览器尚在开发中,所以暂时不能直接在生产环境使用,现阶段浏览器端开发,可以使用 isomorphic-fetch 替代。
传统 XMLHttpRequest 请求网络
|
|
上面是一个典型的 XMLHttpRequest 请求发起流程。
使用 fetch 请求网络
|
|
注:需要提前安装 isomorphic-fetch。
上面的代码还可以进一步简写成:
|
|
async & await
上面的写法流程看起来更加清晰,但是仍然是 Callback 的写法,可以使用 async 和 await 处理 fetch ,让整个流程就像是同步流程一样。
|
|
使用 await 后,写异步代码就像写同步代码一样。await 后面可以跟 Promise 对象,表示等待 Promise resolve() 才会继续向下执行,如果 Promise 被 reject() 或抛出异常则会被外面的 try…catch 捕获。
fetch 语法
Promise
fetch(input[, init]);
两个参数 input 和 init,input 可以是请求的地址,也可以是一个 request 请求对象。
可选参数 init
一个配置项对象,包括所有对请求的设置。可选的参数有:
- 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=)。
返回值
fetch 返回一个 Promise,resolve 时回传 Response 对象。
Response
可以使用 Response.Response() 构造函数来创建一个 Response 对象,但通常会是其他的 API 操作返回了一个 Response 对象,例如一个 service worker 的Fetchevent.respondWith,或者一个简单的 GlobalFetch.fetch()。
constructor
Response.Response() // 创建一个 Response 对象
attr & method
- Response.ok 包含了一个布尔值来标示该Response成功(状态码200-299) 还是失败
- Body.json() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为JSON格式的promise对象
- Body.text() 读取 Response对象并且将它设置为已读(因为Responses对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为USVString格式的promise对象
版本兼容
fetch 原生支持率不高,幸运的是,引入下面这些 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 polyfill 的基本原理是探测是否存在 window.fetch 方法,如果没有则用 XHR 实现。这也是 github/fetch 的做法,但是有些浏览器(Chrome 45)原生支持 Fetch,但响应中有中文时会乱码,老外又不太关心这种问题,所以我才有了 fetch-detector 和 fetch-ie8 只在浏览器稳定支持 Fetch 情况下才使用原生 Fetch。