HTTP 缓存模型中,如果请求成功会有三种情况:
-
200 from cache:直接从本地缓存中获取响应,最快速,最省流量,因为根本没有向服务器发送请求。
- 304 Not Modified:协商缓存。浏览器在本地没有命中的情况下于请求头中发送一定的校验数据到服务端,如果服务端数据没有改变,浏览器从本地缓存响应,返回 304。
- 200 OK:以上两种缓存全都失败,服务器返回完整响应。没有用到缓存,相对较慢。
本地缓存相关 header(优先级 Pragma > Cache-Control > Expires):
Pragma:HTTP1.0 时代的遗留产物,该字段被设置为 no-cache 时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求。
Expires:HTTP1.0 时代用来启用本地缓存的字段,expires 值对应一个形如 Sat, 01 May 2021 08:05:53 GMT 的格林威治时间,告诉浏览器缓存失效的时刻,
如果还没到该时刻,表明缓存还有效,无需发送请求。缺点:返回的到期时间是服务器端的时间。这样存在一个问题,如果客户端的时间与服务器端的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大。
Cache-Control:HTTP1.1 针对 Expires 时间不一致的解决方案。运用 Cache-Control 告知浏览器缓存过期的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存的管理。
常用参数:
- Public/Private:私有缓存/共有缓存。
- no-store:禁止浏览器响应缓存。
- no-cache:不允许直接使用本地缓存,先发起请求和服务器协商。
- max-age=delta-seconds:告知浏览器该响应本地缓存有效的最长期限,以秒为单位。
协商缓存相关 header:
Last-Modified(响应头):告知浏览器资源的最后修改时间。
If-Modified-Since(请求头):得到资源的最后修改时间后,会将这个信息通过 If-Modified-Since 提交到服务器做检查,如果没有修改,返回 304 状态码。
ETag(响应头):文件的指纹标识符(HTTP1.1 推出),如果文件内容修改,指纹会改变。
If-None-Match(请求头):如果本地缓存失效,会携带此值去请求服务端,服务端判断该资源是否改变,如果没有改变,直接使用本地缓存,返回 304。
适合本地缓存的文件:不变的图片,如 logo、图标等;css、js 静态文件;可下载的内容、媒体文件。
适合协商缓存的文件:HTML 文件;经常替换的图片、css、js 文件。
PHP 模拟协商缓存
<?php if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && (strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) + 3600 > time())) { header('HTTP/1.1 304 Not Modified'); exit; } // gmdate:返回的时间是格林威治标准时(GMT) header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); echo date('Y-m-d H:i:s');