同步各个浏览器的书签(校导李凡〡浏览器缓存那些事儿)
计算机科学中最难的两件事是缓存失效和命名。
-- Phil Karlton
今天我们来简要了解一下浏览器的缓存问题。
浏览器缓存是指当浏览器请求一个资源的时候,会在本地保存一份副本,当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。
一 浏览器缓存的作用
1. 减少网络带宽消耗:无论对于网站运营者或者用户,带宽都代表着金钱,过多的带宽消耗,只会便宜了网络运营商。当Web缓存副本被使用时,只会产生极小的网络流量,可以有效的降低运营成本。
2. 降低服务器压力:给网络资源设定有效期之后,用户可以重复使用本地的缓存,减少对源服务器的请求,间接降低服务器的压力。同时,搜索引擎的爬虫机器人也能根据过期机制降低爬取的频率,也能有效降低服务器的压力。
三 浏览器缓存的控制
1. 使用 Meta 标签控制页面缓存
前端攻城狮可以在HTML页面的节点中加入标签,代码如下:
<meta http-equiv="Pragma" content="no-cache">
上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。所以并不推荐使用这种方式控制页面缓存。
2.使用 HTTP 协议头控制页面缓存
在HTTP请求和响应的消息报头中,常见的与缓存有关的消息报头有以下这些:
Cache-Control 与 Expires
Cache-Control 与 Expires 的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过 Cache-Control 的选择更多,设置更细致,如果同时设置的话,其优先级高于 Expires。
Last-Modified/ETag 与 Cache-Control/Expires
配置 Last-Modified/ETag 的情况下,浏览器再次访问统一 URI 的资源,还是会发送请求到服务器询问文件是否已经修改,如果没有,服务器会只发送一个304回给浏览器,告诉浏览器直接从自己本地的缓存取数据;如果修改过那就整个数据重新发给浏览器。
Cache-Control/Expires 则不同,如果检测到本地的缓存还是有效的时间范围内,浏览器直接使用本地副本,不会发送任何请求。两者一起使用时,Cache-Control/Expires 的优先级要高于 Last-Modified/ETag。即当本地副本根据 Cache-Control/Expires 发现还在有效期内时,则不会再次发送请求去服务器询问修改时间(Last-Modified)或实体标识(Etag)了。
一般情况下,使用 Cache-Control/Expires 会配合 Last-Modified/ETag 一起使用,因为即使服务器设置缓存时间, 当用户点击“刷新”按钮时,浏览器会忽略缓存继续向服务器发送请求,这时 Last-Modified/ETag 将能够很好利用304,从而减少响应开销。
Last-Modified与ETag
你可能会觉得使用 Last-Modified 已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要 Etag(实体标识)呢?HTTP1.1 中 Etag 的出现主要是为了解决几个 Last-Modified 比较难解决的问题:
★ Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的新鲜度。
★ 如果某些文件会被定期生成,当有时内容并没有任何变化,但 Last-Modified 却改变了,导致文件没法使用缓存。
★ 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
Etag 是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified 与ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回304。
四 浏览器缓存机制在实际开发中的应用
服务器端可以设置缓存规则,但在服务器不能掌控的地方也许会出现一些意外。
1. 缓存会被挤出。
所谓缓存被挤出,因为浏览器的缓存空间是有限的,所有网站希望缓存的文件都塞在里面,形成一个先进先出的队列。所以你即使设置了20年的缓存时间,也基本上是不可能保证有那么久的生命期。而且用户也有可能主动清除浏览器缓存,某些系统清理软件也可能清理浏览器缓存。
2. 文件有可能在运营商服务器上被劫持。
第二个问题是用户的宽带运营商为了提高速度,可能会在自己某节点服务器上缓存你的文件(比如 style.css?v1),好处是当用户请求这个文件的时候,运营商无需来你的服务器上请求文件,而自己直接就给出了。 如果你的 querys string 更新了(style.css?v2),按照HTTP规范,这理应被视作一个新的文件。
但是运营商仍然可能会拿自己的缓存,而不是遵循规范。有点可恶对不对?这就是我们在用户量极大的情况下侦查到的情况,所以,为了保证更新的文件确定能下发到所有的用户,我们最好是在资源文件改变时,使用前端构建工具修改文件名,而不是仅修改 query string。
以下是业界公认的最佳规则:
对于动态生成的html页面使用HTTP头:Cache-Control: no-cache
对于静态html页面使用HTTP头:Last-Modified
其他所有的文件类型都设置Expires头,并且在文件内容有所修改的时候修改文件名
作者简介:李凡,英文名Levy,校导Web前端工程师,热衷钻研前端技术,对单页应用开发和前端工程化有着浓厚的兴趣。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com