HTTP 缓存

现在的网络环境相比以前已经变得很好,其实不是太大的网页应用,不是运行在4G以下模式的手机上,一些速度优化的作用越来越少,一些沿用很久的优化理论可能已经不实用。

我希望提供更多具有时代意义的优化建议,本文主要借鉴这篇 文章的优化建议。

良好的HTTP缓存

1.使用Etag 验证缓存的相应

ETag的原理是,在请求文件时,服务器会生成并返回一个随机令牌(一般为文件哈希值)。客户端在下次请求时将令牌发送给服务器,如果令牌一致,则跳过下载。

客户端会先校验ETag若相应未被修改,则在延用Cache-Control的设置时间。

在HTML5 Boilerplate中给出了流行服务器的配置样例

2.确定网站的最佳缓存层级

Cache-Control

每个资源都可以通过 Cache-Control HTTP 头来定义自己的缓存策略
Cache-Control 指令控制谁在什么条件下可以缓存响应以及可以缓存多久

Cache-Control W3c描述文档

Cache-Control 头在 HTTP/1.1 规范中定义,取代了之前用来定义响应缓存策略的头(例如 Expires)。当前的所有浏览器都支持 Cache-Control,因此,使用它就够了。

默认请求资源会被缓存的,我们可以通过设置来修改是否缓存和明确缓存方式。

no-cache 表示必须咸鱼服务器确认返回的相应是否被更改,然后才能使用该响应来满足后续的请求。如果设置了验证令牌,no-cache会发起往返通讯来验证缓存的响应,如果未更改,则不下载。

no-store 直接禁止浏览器和所有中继缓存(CDN)返回的任何版本的响应,每次都会下载完整的响应。

public 表示即使有关联的http认证,甚至响应状态码无法正常缓存,响应也可以被缓存,大多数情况下,public不是必须的,因为明确的缓存信息(如max-age)已表示响应可以被缓存。

private 表示浏览器可以缓存private的响应,但是通常只为单个用户缓存,因此不允许任何中继缓存(如CDN)对其进行缓存。

max-age 该指令指定从当前请求开始,允许获取的响应被重用的最长时间(单位为秒)。

缓存的层级关系

下面这张图展示缓存的作用层级关系

设置合理的缓存级别

对于网页应用我们既有缓存来优化加载,又希望我们的更新能使用户立即获得,对于一些大型的网页应用,在大的版本迭代中,若不能配合server及时更新前端代码,还可能造成应用无法使用的情况。

  • 这是一个典型的层级加载优化事例,在入口的Html文件我们设置no-cache,这意味着每次请求时都会重新验证文档,若内容改变,会获取最新的版本。同时若css,js文件修改,通过指纹码修改css和js文件的文件名,入口的Html文件会随之更新,下载新的版本。

  • 允许浏览器中继缓存 css 过期时间设置为1年。这是我们可以放心设置较长的时间,因为css的更新会同时更新网址,保证立即更新。

  • JavaScript 过期时间也设置为一年,但是被标记为private, 因为JavaScript可能包含一些个人数据,但是一般情况情况下private也是不需要的。

  • 缓存图片是不包含版本或指纹码,过期时间设为一天。 这样做是会存在风险图片不能及时更新,例如css引用的图片更新,为了及时更新我们也需要给图片添加指纹码,之后我们可以放心的设置较长的缓存时间。

其他优化

  • 同一资源使用相同的网址
  • 利用CDN等中继缓存常用公共资源
  • 更新最小化,经常更新的部分,考虑单独拉出文件,仅作这部分更新

问题&BUG

上面所讲的理论在实践中,在不同浏览器、webview中并不一定如我们所愿的那样运作。可能会出现各种各样关于缓存的问题。在遇到具体问题时,会在下文具体分析解决。