HTTP缓存是指浏览器或者代理服务器将已经请求过的资源保存到本地,以便下次请求时能够直接从缓存中获取资源,从而减少网络请求次数,提高网页的加载速度和用户体验。缓存分为强缓存和协商缓存两种模式。
一. 强缓存
强缓存是指浏览器直接从本地缓存中获取资源,而不需要向web服务器发出网络请求。这是因为浏览器在第一次请求资源时,服务器会在响应头中添加相关缓存的响应头,以表明该资源的缓存策略。
常见的强缓存响应头如下所述:
- Cache-Control
Cache-Control 响应头是用于控制强制缓存和协商缓存的缓存策略。该响应头中的指令如下:
- max-age:指定该资源在本地缓存的最长有效时间,以秒为单位。例如:Cache-Control: max-age=31536000(代表该资源在本地缓存中一年内有效)。
- no-cache:代表该资源需要进行缓存,但是在使用前需要向服务器发送请求,以此让服务器根据 If-Modified-Since 或 If-None-Match 判断该资源是否更新,以此决定是否使用本地缓存。
- no-store:代表禁止使用任何形式的缓存,每次请求都需要重新向服务器发送请求。
例如,下面是一个 Cache-Control 响应头的示例:
Cache-Control: public, max-age=31536000
其中,public 表示该资源在客户端和代理服务器中均可以缓存,max-age=31536000 表示该资源在本地缓存中一年内有效。
- Expires
Expires 响应头在 HTTP / 1.0 中被广泛使用,用于指定资源的到期时间,以确保浏览器不会在过期日期之后再次发送请求。
例如,下面是一个 Expires 响应头的示例:
Expires: Tue, 30 Dec 2030 12:00:00 GMT
其中,Expires 表示该资源的到期时间为 Tue, 30 Dec 2030 12:00:00 GMT。
二. 协商缓存
协商缓存是指在使用缓存之前,浏览器需要向服务器发起网络请求,以此根据服务器返回的响应头中的 ETag 或 Last-Modified 字段来判断该资源是否更新,进而决定是否使用本地缓存。
常见的协商缓存响应头如下所述:
- ETag
ETag 是一个 Web 服务器为每个资源分配的唯一标识符,用于判断该资源是否更新。例如,下面是一个 ETag 响应头的示例:
ETag: “123456789”
其中,“123456789” 是该资源的唯一标识符。 - Last-Modified
Last-Modified 是资源在服务器上最后被修改的时间戳,也用于协商缓存。例如,下面是一个 Last-Modified 响应头的示例:
Last-Modified: Fri, 01 Jan 2021 00:00:00 GMT
在协商缓存中,浏览器请求服务器时,会在请求头中添加 If-None-Match(代表当前本地缓存中资源的 ETag 值)和 If-Modified-Since(代表当前本地缓存中资源的 Last-Modified 时间戳)字段,告诉服务器自己本地缓存的该资源的 ETag 和 Last-Modified 时间戳。服务器收到请求后,会根据请求头中的这些字段和资源的当前 ETag 和 Last-Modified 时间戳,来判断该资源是否更新。
如果资源未更新,则服务器返回 304 Not Modified 响应码,表示不需要重新下载资源,可以直接使用本地缓存。如果资源已更新,则服务器返回新的资源,并更新浏览器的本地缓存。
三. 示例
下面通过一个实际的案例来展示 HTTP 缓存的具体应用。假设有一个服务器上的图片资源,其地址为 https://example.com/img/logo.png,其相关信息如下:
- 大小:10KB
- 修改时间:2021/05/20 10:10:10
- ETag:“123456”
- 缓存策略:Cache-Control: max-age=3600
当浏览器首次发起请求时,服务器会将响应头中的 Cache-Control 和 ETag 值返回给浏览器,如下所示:
HTTP/1.1 200 OK
Cache-Control: max-age=3600
ETag: "123456"
Content-Length: 10240
Content-Type: image/png
<binary image data...>
浏览器接收到响应头中的相关信息后,将资源保存到本地缓存中。当浏览器再次请求这个资源时,浏览器会先检查本地缓存中是否有该资源的缓存条目,如果有,则会直接返回本地缓存中的数据;如果没有,则会向服务器发起请求。
浏览器在发起请求时,会将 If-None-Match 和 If-Modified-Since 字段添加到请求头中,告诉服务器自己本地缓存的该资源的 ETag 和 Last-Modified 时间戳,如下所示:
GET /img/logo.png HTTP/1.1
Host: example.com
If-None-Match: "123456"
If-Modified-Since: Thu, 20 May 2021 10:10:10 GMT
服务器接收到请求后,会根据请求头中的 If-None-Match 和 If-Modified-Since 字段和资源的当前 ETag 和 Last-Modified 时间戳,来判断该资源是否更新。如果资源未更新,则服务器返回 304 Not Modified 响应码,表示不需要重新下载资源,可以直接使用本地缓存。如果资源已更新,则服务器返回新的资源,并更新浏览器的本地缓存。