在日常开发中,用 fetch 发起网络请求已经成了家常便饭。但很多人可能没太注意,fetch 请求到底会不会走缓存?简单说:fetch 的缓存行为和浏览器的常规请求一致,默认会遵循 HTTP 缓存策略,也就是说,它不是完全禁用缓存,也不是每次都强制刷新。
默认行为:走 HTTP 缓存流程
当你写一段最简单的 fetch 代码:
fetch('/api/data')
这和你在浏览器地址栏输入 URL 或者用 <img> 标签加载图片一样,都会走浏览器的缓存机制。如果服务器返回了 Cache-Control、ETag 或 Last-Modified 这类头信息,浏览器就会根据这些规则判断是否读取缓存,而不是发起新的请求。
什么时候会命中缓存?
比如你第一次请求某个配置文件:
fetch('/config.json')
服务器返回时带了 Cache-Control: max-age=60,那么接下来 60 秒内再次调用同样的 fetch,浏览器很可能直接从内存或磁盘缓存中拿结果,根本不会发出去。这对提升性能是好事,但也可能带来“数据没更新”的错觉。
如何避免缓存?手动控制更稳妥
如果你希望每次请求都拿到最新数据,比如提交表单后的查询、实时状态轮询,那就得主动干预缓存行为。可以通过 cache 选项来控制:
fetch('/api/data', { cache: 'no-store' })
这样浏览器就不会读缓存,也不会存缓存,每次都会真实请求服务器。
另一种常见做法是加时间戳或随机参数:
fetch(`/api/data?t=${Date.now()}`)
虽然有点“土”,但在老项目里很实用,尤其是后端没配好缓存头的时候。
想用缓存?也得看后端配合
就算你设置了 cache: 'default',也不代表一定能缓存。最终还得看响应头是否允许。如果后端返回 Cache-Control: no-cache 或 no-store,那浏览器也只能乖乖去请求服务器。
所以,别以为用了 fetch 就自动避开缓存,也别以为不加参数就一定有缓存。实际表现,是前端配置和后端头信息共同决定的。
开发时如果发现数据“卡住不动”,不妨打开 DevTools 看一眼 Network 里的请求状态,如果是 304 Not Modified 或 memory cache,就知道是缓存在起作用了。