随着 PWA 进入人们的视野,Fetch 作为除了 AJAX 之外的第二个 JavaScript HTTP API 开始引起人们的关注。Service Worker 中通常利用该 API 进行真正的网络请求并应用相应的缓存策略。 本文简要介绍 Fetch API 的使用,Service Worker 与 Window 中的实现差异,以及跨域 Fetch 的问题。
目前 web 异步应用都是基于
/
- XMLHttpRequest
实现的, 这些对象不是专门为资源获取而设计的,因而它们的 API 非常复杂,同时还需要开发者处理兼容性问题。 虽然开发者普遍使用
- ActiveXObject
这样的上层包装,但 Fetch API 意在提供更加方便和一致的原生 API, 同时统一 Web 平台上的资源获取行为,包括外链脚本、样式、图片、AJAX 等等。
- $.ajax()
Fetch 方法 是 Fetch API 的核心方法,同时定义在
和
- window
, 因此可以作为通用的方法来使用。在 Fetch 标准 中该方法的声明如下。
- WorkerGlobalScope
- partial interface WindowOrWorkerGlobalScope {
- [NewObject] Promise<Response> fetch(RequestInfo input, optional RequestInit init);
- };
方法返回一个 Promise,因此使用起来非常有现代感:
- fetch
- fetch('http://harttle.com')
- .then(function(res) {
- // 使用该 HTTP 响应
- }).catch(function(err) {
- // 处理错误 err
- });
方法的第二个参数是一个参数对象,用来初始化 Request。下面列出了几个重要的属性:
- fetch
:请求方法,可取
- method
,
- "GET"
等,默认为
- "POST"
。
- "GET"
:请求模式,可取
- mode
,
- "no-cors"
,
- "cors"
。
- "same-origin"
:是否携带 Cookie,可取:
- credentials
,
- "omit"
,
- "same-origin"
。
- "include"
: 缓存模式,可取:
- cache
,
- default
,
- no-store
,
- reload
,
- no-cache
,
- force-cache
。
- only-if-cached
简单的使用方法如下:
- fetch('http://harttle.com', {
- method: 'GET',
- mode: 'no-cors',
- cache: 'default'
- })
是 Service Worker 实现中最重要的参数,它的值可能是:
- mode
: 采用跨域资源共享的方式去获取。要求对方服务器启用了 CORS 响应头,可以读取响应内容。否则会跨域失败。
- cors
:采用非跨域资源共享的方式去获取。不要求对方的 CORS 设置,不可读取响应内容。
- no-cors
:采用同域的方式去获取,如果 URL 跨域就会失败。
- same-origin
更多参数解释参考: https://developer.mozilla.org/zh-CN/docs/Web/API/GlobalFetch/fetch
Service Worker 实现离线缓存时,通常需要监听
事件并应用缓存。
- fetch
事件作用于当前受控制的页面,既可以拦截同域的请求也可以拦截跨域的请求。 这意味着
- fetch
的页面请求
- harttle.org
中的资源时,
- harttle.com
的 Service Worker 会收到
- harttle.org
事件,但
- fetch
的 Service Worker 不会 (在启用了 Foreign Fetch 的 Service Worker 中,情况可能略有不同)。
- harttle.com
在跨域资源请求的情况下,Service Worker 中进行 Fetch 和写 CacheStorage 操作都可以成功。 但需要注意的是 Fetch API 的设计比 AJAX 更为底层,但二者的 CORS 策略是一致的。 具体地,如果 Fetch 时声明了
就可以跨域 Fetch,其代价是无法读取响应状态码和响应体内容。
- no-cors
- fetch('http://harttle.com/foo.jpg', {
- mode: 'no-cors'
- }).then(res = >{
- if (!res.ok) return;
- caches.open('harttle').then(cache = >{
- cache.put('http://harttle.com/foo.jpg', res)
- })
- })
虽然跨域情况下无法知晓响应体和状态码,但考虑到 Service Worker 需要了解 Fetch 是否成功来进行缓存,
给出了
- Response
属性来判断获取成功与否。
- .ok
参见 Harttle 的 Demo: https://demo.service-worker.org/cors-fetch/
第二个参数的
- fetch
属性的默认值在 Chrome 中实现不一致。 根据 Fetch API 标准 ,该参数的默认值为
- credentials
, 即同域时携带 Cookie(这一点
- same-origin
与
- fetch
的表现一致)。
- XMLHttpRequest
但 Chrome 目前的实现中(Harttle 的版本是 56.0.2924.87 64-bit),
默认不带 Cookie,即
- window.fetch()
;
- omit
则默认携带 Cookie,即
- ServiceWorkerGlobalScope.fetch()
。
- same-origin
为了避免不一致的 Bug,建议总是给
设置
- fetch
参数:
- credentials
- fetch('http://harttle.com', {
- credentials: 'same-origin'
- }).then(res = >{
- // 处理 Response
- })
参见 Harttle 的 Demo: https://demo.service-worker.org/fetch-with-credentials/
第二个参数的
- fetch
属性在 Chrome 下默认值不正确。 根据 WHATWG 的 Fetch API 标准 ,Request 的模式(
- mode
)默认值为
- mode
:
- "no-cors"
2.2.5. Requests
A request has an associated mode, which is "same-origin", "cors", "no-cors", "navigate", or "websocket". Unless stated otherwise, it is "no-cors".
Even though the default request mode is "no-cors", standards are highly discouraged from using it for new features. It is rather unsafe. "navigate" and "websocket" are special values for the html Standard. [HTML]
Chrome 下默认值为
,这会导致用默认参数
- "cors"
未开启 CORS 的跨域资源时失败。 因此在编写 Service Worker 时,如果无需读取 Response 内容,要显式地声明
- fetch
。
- mode: 'no-cors'
参见 Harttle 的 Demo: https://demo.service-worker.org/cors-fetch/
下面是 Fetch API 相关标准、文档、以及本站的其他文章。
来源: http://www.tuicool.com/articles/vmY3euJ