浏览器缓存机制
本文整理在,我的github上。要是对您有帮助,就点歌星星呗。我会持续更新的。
关于3xx系列的状态码
- 300 多资源选择
- 301 永久重定向
- 302 临时重定向
-
303 告诉用户,使用另一个url获取资源
主要目的是允许post请求的响应将客户端定位到某个资源上。比如说,在文件上传完成后让客户端自动重定向到一个上传成功的结果页面。
- 307 通知用户临时从其他url响应,重定向的页面展示给用户,让用户去点重定向url链接。
-
304 服务端没有变更
通知浏览器,可以使用缓存。这篇博文要描述的重点
浏览器(http)缓存机制
类型
说到浏览器缓存,通常会遇到一下两种。
- 200(from cache)
- 304
那么,这两种http状态,对应什么样的机制,流程呢?
缓存机制
综合以上描述,浏览器在请求一个资源时,使用缓存的流程大概如下。
-
首先浏览器会判断,这个资源是否有缓存。没有的话,正常请求。
-
如果有缓存的话,浏览会判断缓存是否过期。如果缓存没有过期,则直接使用。此时就是 200(from cache)。
通过上次缓存留下的:cache-control max-age 和 expires。
注意:cache-control的优先级高于expires。 -
如果浏览器的缓存过期了,它会请求服务器。服务器会校验缓存的数据是否真的发生了更改。如果服务器端发现数据没有变。就会返回一个304告诉浏览器,你请求的数据 “not modified”,可以继续用缓存。同时,浏览器会更新缓存首部的过期时间等信息。
这里浏览器发起请求时,会用到上次缓存首部的last-modified/e-tag。
具体做法是:
取出上次缓存的last-modified的值,放在本次请求header的 if-modified-since 中。
取出上次缓存的e-tag的值,放在本次请求header中的 if-none-match 中。
服务器会据此判断资源是否发生过修改,浏览器中的缓存是否依然可用。 -
如果服务器端修改了上次缓存的内容,则直接返回200,并携带新的内容。
相关http头
上文中提到了几个http头,这里做一下详细的解释。
cache-control
- public: 所有内容都将被缓存
- private: 内容只缓存到似有缓存中
- no-cache: 所有内容都不会被缓存
- no-store: 所有内容都不会被缓存到缓存或者internet临时文件中
- must-revalidation/proxy-revalidation: 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证(主要用于控制浏览器的前进、后退)
-
max-age=xxx( xxx is numeric ): 缓存的内容将在 xxx 秒后失效, 这个选项只在http 1.1可用, 并如果和last-modified一起使用时, 优先级较高
expires
头部字段提供一个日期和时间。
(cache-control max-age 和 s-maxage 将覆盖 expires 头部。)last-modified/e-tag
-
若服务器在响应一个资源时添加了last-modified字段,那么当下一次浏览器再一次向服务器请求该资源时(前提是浏览器中上一次的资源被缓存过了),会在请求header中包含if-modified-since字段,且值与服务器第一次响应给浏览器的last-modified字段一致。
-
若服务器在响应一个资源时添加了etag字段,那么当下一次浏览器再一次向服务器请求该资源时(前提是浏览器中上一次的资源被缓存过了),会在请求header中包含if-none-match字段,且值与服务器第一次响应给浏览器的etag字段一致
那么上述是遵循了http协议的浏览器会自动实现的,而要实现304的功能,就需要服务器(比如apache对于静态资源会自动实现这两个字段的响应)或者我们手动在服务器端编写响应的逻辑来实现。
写到这,整个浏览器及http缓存机制应该彻底介绍清楚了。
那么,就只剩下如何应用了。
原理与应用
静态资源
所谓静态资源,就是很少会修改的内容,包括前端常年打交道的css、js及图片文件等等。
通常情况下,静态资源的http头是这样配置的。
cache-control: public, max-age=31536000 expires: (一年后的今天) etag: (基于内容生成) last-modified: (过去某个时间) vary: accept-encoding
到这里,可以据此给站点中全部的静态资源配置缓存头。这里我有两个建议。
- 建议给每个静态资源路径添加指纹信息。可以使用gulp或者webpack等构建工具。通过不同版本的指纹信息控制更新缓存。
- 项目中引用的依赖,建议使用cdn资源。依据缓存原理,浏览器只要访问过相同cdn的资源,就会留下缓存,哪怕其他站点。
动态资源
基础配置
对于非私密性和经常性变动的资源,我们可以这样做。
cache-control: public, max-age=0 expires: (当前时间) etag: (基于内容生成) last-modified: (过去某个时间) vary: accept-encoding
这样配置的意义在于,内容可以被浏览器缓存起来。但是因为过期时间的问题,每次都会到服务端判断是否过期。未过期的话,就会收到304,进而继续使用缓存。
控制返回、前进
你如果需要更严格的控制,需要告知浏览器即使当用户点击了「返回/前进」按钮,也需要重新检查这些资源文件,那么可以使用:
cache-control: public, no-cache, no-store
私密性缓存
对于私密或者针对用户的内容,需要把 public 替换为 private 以避免内容被代理缓存。
cache-control: private, …
关于etag
建议避免使用 etag。尤其是使用apache,又配置了负载均衡的情况下。
针对生成的 etag,默认的apache方法需要把文件的索引节(inode),大小(size)和最后修改时间作为输入求值得到。这会导致在负载均衡的环境中,生成的 etag 值变得毫无用处,因为每个服务器都会针对相同的文件生成一个不同的 etag 值。这个可能就是唯一的问题导致很多人完全禁用 etag,其实只要精确地针对一个匹配的文件生成一个独一无二的 etag 值,就没有必要禁用 etag 了。
vary: accept-encoding
指定“vary: accept-encoding”标头,用一句话来说明它的意义,就是“告诉代理服务器缓存两种版本的资源:压缩和非压缩,这有助于避免一些公共代理不能正确地检测content-encoding标头的问题。
还有一个现实的原因:ie 浏览器不缓存任何带有 vary 头但值不为 accept-encoding 和 user-agent 的资源。所以通过这种方式添加这个头,才能确保这些资源在 ie 下被缓存。
总的来说,加这么一句肯定没错,相当于“多喝热水”。
下一篇: python实现Zabbix-API监控
推荐阅读
-
ThinkPHP文件缓存类代码分享_PHP
-
PHP实时输出报文到浏览器
-
GD2绘制图形在浏览器中不能展示
-
Scrapy各部分运行机制?Xpath为None?多层Response如何编写?搞定Scrapy的坑
-
请教PHP有什么好的缓存吗
-
Selenium3 + Python3自动化测试系列一——安装Python+selenium及selenium3 浏览器驱动
-
PHP常用的缓存技术汇总_PHP
-
php MemCache内存缓存学习笔记_PHP教程
-
用户关闭浏览器后服务器端会继续执行吗?
-
发布BlueShow v1.0 图片浏览器(类似lightbox)blueshow.js 打包下载_javascript技巧