强缓存
强缓存是浏览器缓存机制中的一种策略,通过设置缓存资源的过期时间,使得客户端可以在一定时间内直接从本地缓存获取资源,而无需向服务器发送请求
。
强缓存主要使用两个响应头字段来控制缓存的过期时间:Expires
和 Cache-Control
。
1. Expires
Expires
是一个指定缓存过期时间的响应头字段,它的值是一个绝对时间,表示资源在该时间之前有效。- 当客户端再次访问相同的资源时,会检查该资源的
Expires
字段与客户端本地时间的对比,如果当前时间在Expires
的时间之前,客户端会直接从本地缓存获取资源。 - 弊端是依赖于客户端本地时间的准确性,如果客户端本地时间与服务器不同步,那么缓存可能会失效,导致客户端发送不必要的请求。
2. Cache-Control
- Cache-Control 是一个更为灵活的响应头字段,用于控制缓存的行为。它可以指定缓存的
最大存储时间
(max-age),也可以使用其他指令来控制缓存的行为。 - max-age 指令表示资源在被认为“新鲜”的一段时间内有效,单位为秒。例如,Cache-Control: max-age=3600 表示资源在被认为有效的一小时内不需要进行验证。
- Cache-Control 还包括其他指令,如
public、private、no-cache、no-store
等。其中,no-cache 表示资源需要校验才能使用,而 no-store 则表示不缓存该资源。
在使用强缓存时,浏览器会首先检查是否存在合适的缓存副本。如果缓存有效,则可以直接使用缓存,从而减少了网络传输和服务端处理的开销
,提升了网页加载速度和用户体验。只有当缓存失效或过期时,浏览器才会向服务器发送请求,获取最新的资源。
需要注意的是,Cache-Control
的优先级高于 Expires
。当同时出现这两个字段时,浏览器会优先使用 Cache-Control
字段来判断缓存的有效性。
强缓存是一种简单有效的缓存策略,但也有一些潜在的问题,如缓存资源更新时客户端无法及时获取到最新版本的资源。因此,在某些情况下,协商缓存机制配合强缓存可以更好地实现缓存控制和更新。
协商缓存
协商缓存是浏览器缓存机制中的另一种策略,通过与服务器进行通信,判断缓存的资源是否有效,从而决定是否需要重新获取资源。
协商缓存主要使用两对请求头和响应头来进行判断:Last-Modified
/ If-Modified-Since
和 ETag
/ If-None-Match
。
1. Last-Modified / If-Modified-Since
- 当服务器响应资源时,会在响应头中添加
Last-Modified
字段,该字段表示资源的最后修改时间。 - 当客户端再次请求该资源时,在请求头中添加
If-Modified-Since
字段,将上一次获取到的Last-Modified
时间值传递给服务器。 - 服务器收到该请求后,会将
If-Modified-Since
字段的值与资源的实际最后修改时间进行对比。 - 如果资源的最后修改时间早于或等于
If-Modified-Since
字段指定的时间,则返回304 Not Modified
状态码,告诉客户端可以继续使用缓存的资源。 - 否则,服务器将返回最新的资源,并在响应头中更新
Last-Modified
字段。
2. ETag / If-None-Match
ETag
是服务器生成的唯一标识符,通常是根据资源内容计算得出的哈希值。服务器在响应头中添加ETag
字段。- 当客户端再次请求该资源时,在请求头中添加
If-None-Match
字段,将上一次获取到的ETag
值传递给服务器。 - 服务器收到该请求后,会将
If-None-Match
字段的值与当前资源的 ETag 进行对比。 - 如果两者匹配,则返回
304 Not Modified
状态码,客户端可以继续使用缓存的资源。 - 如果不匹配,则返回最新的资源,并在响应头中更新
ETag
字段。
协商缓存通过与服务器进行交互,避免了无效的资源传输,减少了网络开销。相比强缓存,协商缓存更具灵活性,因为它不仅仅依赖于缓存的过期时间,还考虑了资源的实际修改情况。
需要注意的是,服务器必须正确地实现 Last-Modified / If-Modified-Since
和 ETag / If-None-Match
的逻辑,确保生成的标识符和时间戳能够准确反映资源的状态变化。同时,协商缓存还涉及到一些算法和性能优化的问题,如一些服务器会禁用 ETag,以减少计算开销。
综合使用强缓存和协商缓存,可以更好地控制缓存策略,提高网页加载速度和用户体验。
Service Worker 缓存
Service Worker
缓存是一种基于浏览器的 Web API
,它可以在后台运行,并拦截网络请求,提供一种可编程的缓存机制。使用 Service Worker
可以实现更高级的缓存策略和离线访问能力。
下面是 Service Worker 缓存的详细介绍:
1. 注册和安装
- 首先,在网页的
JavaScript
文件中注册Service Worker
,并指定Service Worker
脚本文件的路径。 - 然后,在
Service Worker
脚本文件中,通过监听install
事件来进行安装操作。在安装过程中,可以预先缓存一些静态资源,以便离线访问。
2. 缓存策略
- 在
Service Worker
中,可以自定义缓存策略,决定哪些资源需要缓存、如何缓存以及如何回应请求。 - 可以通过
Cache API
来存储和检索缓存的资源。可以使用caches.open()
方法打开一个缓存对象,并使用cache.put()
方法将资源添加到缓存中,或者使用cache.match()
方法来查找缓存中的资源。 - 缓存策略可以根据资源的 URL、请求头或其他条件进行灵活配置,例如可以实现基于缓存版本的更新策略,或者根据网络状态选择不同的缓存策略。
3. 缓存更新
- 当用户发起请求时,
Service Worker
可以拦截请求并决定如何响应。 Service Worker
可以在缓存中查找请求的资源,并根据缓存策略判断是否直接使用缓存或者重新从网络获取最新版本的资源。- 如果需要更新缓存中的资源,可以通过
fetch()
方法来获取最新的资源,并将其添加到缓存中。然后,可以使用cache.put()
方法来更新缓存。
4. 离线访问
- 由于
Service Worker
可在离线状态下运行,因此可以实现离线访问能力。 - 在安装
Service Worker
时,可以预先缓存一些核心资源,使得用户在离线时仍然可以浏览部分内容。 - 当用户在离线状态下发起请求时,
Service Worker
可以拦截请求并返回缓存中的内容,从而实现离线访问。
Service Worker 缓存提供了更高级的控制和灵活性,使得网页可以在离线状态下加载,并可根据自定义的缓存策略来处理资源的请求和更新。然而,使用 Service Worker 缓存也需要谨慎对待,确保缓存的资源及时更新,避免过期的缓存导致用户获取不到最新的内容。
浏览器缓存对比
下面是关于浏览器缓存的简单归纳表格:
类型 | 描述 | 优点 | 缺点 |
强缓存(Expires) | 使用 Expires 字段设置缓存的过期时间,基于客户端本地时间 | 不需要向服务器发送请求,可以直接从本地获取缓存的资源 | 如果客户端本地时间与服务器时间不同步,可能导致缓存失效 |
强缓存(Cache-Control) | 使用 Cache-Control 字段设置缓存的过期时间,可以指定相对时间或绝对时间 | 可以更精确地控制缓存的过期时间 | 某些代理服务器或浏览器对 Cache-Control 字段的解析可能存在差异 |
协商缓存(Last-Modified / If-Modified-Since) | 使用 Last-Modified 和 If-Modified-Since 字段进行对比,判断资源是否已经修改 | 减少了不必要的数据传输,避免了重复下载未修改的资源 | 如果文件的修改频率很高(如秒级别),可能导致缓存失效 |
协商缓存(ETag / If-None-Match) | 使用 ETag 和 If-None-Match 字段进行对比,判断资源是否已经修改 | 更精确地判断资源是否有变化,避免了一些 Last-Modified 不准确的问题 | 计算 ETag 需要服务器额外的计算开销,如果服务器未正确处理 ETag,可能导致缓存失效 |
离线缓存(Application Cache) | 使用 Manifest 文件指定哪些资源可以离线缓存 | 可以实现离线访问应用程序,提升用户体验 | Manifest 文件需要单独维护,不够灵活;浏览器对 Manifest 缓存机制的实现存在一些问题,容易造成缓存更新不及时的情况 |
Service Worker 缓存 | 使用 Service Worker 进行资源的缓存和拦截 | 可以自定义缓存策略,实现更高级的缓存控制和离线访问能力 | 需要编写 Service Worker 脚本,涉及到一些复杂的 API 和操作,支持程度有限,兼容性方面存在一些问题 |
需要注意的是,浏览器缓存的机制是复杂且灵活的,具体的使用方式和效果会受到浏览器、服务器配置和响应头等因素的影响。在实际开发中,需要综合考虑缓存的类型、目标用户和需求来选择合适的缓存策略。