在构建现代Web应用时,fetch() API已经成为替代XMLHttpRequest的标准方案。然而,许多开发者在使用中遇到一个常见困惑:我通过fetch发起的请求,其响应能否被浏览器缓存? 这个问题看似简单,背后却涉及HTTP缓存机制、浏览器默认行为以及Service Worker等多个层面。本文将从技术规范与实战角度进行剖析。

一、误解来源:Fetch API默认不缓存

初代fetch设计的目标之一是提供更可控的网络请求方式,因此其默认行为与浏览器传统的页面请求(如<img><link>标签加载资源)存在差异。根据WHATWG Fetch规范,没有显式设置Request.cache模式时,fetch请求遵循“default”策略,该策略在标准HTTP缓存流程中相当于“开发者未主动干预”,但仍会依据响应头(如Cache-ControlExpires)进行缓存。

然而,实际浏览器实现中,许多开发者发现:同一个URL多次fetch,请求依然会发送到服务器,而不是从磁盘缓存中读取。这导致“fetch请求不会被缓存”的错觉。核心原因在于:

  • 浏览器对fetch请求的缓存存储位置与普通资源请求不同,它不会自动存入HTTP缓存中的“Disk Cache”(除非响应明确允许)。
  • 大部分fetch请求默认带有no-cachereload之类的隐式标记,取决于请求模式(如跨域CORS请求)。

二、真相:是否被缓存,取决于响应头与Request.cache设置

实际上,浏览器完全有能力缓存fetch的响应,但开发者必须主动配合HTTP缓存协议。关键控制点有两个:

  1. 服务端返回正确的缓存控制头:例如Cache-Control: max-age=3600。只要响应头允许,浏览器就会按常规流程将响应存入强缓存(memory cache或disk cache)。下回相同URL的fetch请求,会直接返回缓存结果,无需网络请求。

  2. 客户端设置Request.cache属性:fetch接受第二个参数init,其中的cache选项可以覆盖默认行为: - default:依据响应头和缓存状态(浏览器可能不会缓存跨域请求)。 - no-store:完全不使用缓存,也不存入。 - reload:强制从服务器获取,但获取后可以更新缓存。 - no-cache:始终验证缓存有效性。 - force-cache:即使响应过期也优先使用缓存,仅当本地无缓存时才请求网络。 - only-if-cached:仅从缓存获取,若无缓存则报错(需同域或Service Worker)。

因此,若想确保fetch响应被缓存,只需设置cache: 'force-cache',并保证服务器返回了允许缓存的响应头。

三、特殊情况:Fetch与Service Worker的缓存交互

现代PWA(渐进式Web应用)中,开发者常通过Service Worker自定义缓存策略。此时,fetch请求的响应是否被缓存,完全由Service Worker中的fetch事件处理逻辑决定。例如:

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cached => cached || fetch(event.request))
  );
});

这种情况下,即使原始响应头禁止缓存,Service Worker也能主动将响应存入Cache API。因此,在Service Worker作用域内,“缓存费取响应”完全可编程,与浏览器默认行为无关。

四、验证方法:开发者工具实操

要确认当前fetch请求是否被缓存,最简单的方式是打开浏览器开发者工具(F12),在Network面板中查看请求的“Size”列: - 若显示“from disk cache”或“from memory cache”,说明响应已被强缓存。 - 若显示“304 Not Modified”,说明是协商缓存(需验证)。 - 若每次都是实际网络请求(如200 OK),则未被缓存。

另外,在Chrome的Application面板中,展开“Cache Storage”可查看Service Worker管理的缓存;而“Storage”下的“Cache”标签可查看浏览器HTTP缓存。fetch请求的缓存结果,通常出现在“HTTP Cache”或“Disk Cache”中,前提是响应头满足条件。

五、最佳实践建议

  1. 对于公共静态资源(如JSON配置文件、图标):服务端加入Cache-Control: public, max-age=86400,并在fetch时设置cache: 'force-cache'
  2. 对于动态API数据:若希望减少网络延迟,可结合Service Worker实现“stale-while-revalidate”策略,或使用no-cache始终验证。
  3. 测试时留意开发工具“Disable cache”选项:若勾选,所有请求都会绕过缓存,容易导致误判。

结论:fetch请求的响应完全能够被浏览器缓存,但前提是服务端明确表态允许缓存,且客户端没有主动禁止。默认行为并非“不缓存”,而是“遵循HTTP协议标准判断”——但跨域等场景会削弱缓存能力。理解这一机制,有助于开发者更精准地控制应用性能。