在构建现代Web应用时,fetch() API已经成为替代XMLHttpRequest的标准方案。然而,许多开发者在使用中遇到一个常见困惑:我通过fetch发起的请求,其响应能否被浏览器缓存? 这个问题看似简单,背后却涉及HTTP缓存机制、浏览器默认行为以及Service Worker等多个层面。本文将从技术规范与实战角度进行剖析。
一、误解来源:Fetch API默认不缓存
初代fetch设计的目标之一是提供更可控的网络请求方式,因此其默认行为与浏览器传统的页面请求(如<img>、<link>标签加载资源)存在差异。根据WHATWG Fetch规范,没有显式设置Request.cache模式时,fetch请求遵循“default”策略,该策略在标准HTTP缓存流程中相当于“开发者未主动干预”,但仍会依据响应头(如Cache-Control、Expires)进行缓存。
然而,实际浏览器实现中,许多开发者发现:同一个URL多次fetch,请求依然会发送到服务器,而不是从磁盘缓存中读取。这导致“fetch请求不会被缓存”的错觉。核心原因在于:
- 浏览器对fetch请求的缓存存储位置与普通资源请求不同,它不会自动存入HTTP缓存中的“Disk Cache”(除非响应明确允许)。
- 大部分
fetch请求默认带有no-cache或reload之类的隐式标记,取决于请求模式(如跨域CORS请求)。
二、真相:是否被缓存,取决于响应头与Request.cache设置
实际上,浏览器完全有能力缓存fetch的响应,但开发者必须主动配合HTTP缓存协议。关键控制点有两个:
-
服务端返回正确的缓存控制头:例如
Cache-Control: max-age=3600。只要响应头允许,浏览器就会按常规流程将响应存入强缓存(memory cache或disk cache)。下回相同URL的fetch请求,会直接返回缓存结果,无需网络请求。 -
客户端设置
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”中,前提是响应头满足条件。
五、最佳实践建议
- 对于公共静态资源(如JSON配置文件、图标):服务端加入
Cache-Control: public, max-age=86400,并在fetch时设置cache: 'force-cache'。 - 对于动态API数据:若希望减少网络延迟,可结合Service Worker实现“stale-while-revalidate”策略,或使用
no-cache始终验证。 - 测试时留意开发工具“Disable cache”选项:若勾选,所有请求都会绕过缓存,容易导致误判。
结论:fetch请求的响应完全能够被浏览器缓存,但前提是服务端明确表态允许缓存,且客户端没有主动禁止。默认行为并非“不缓存”,而是“遵循HTTP协议标准判断”——但跨域等场景会削弱缓存能力。理解这一机制,有助于开发者更精准地控制应用性能。