善用http缓存 – 杂记

善用http缓存可以提升用户体验和服务器性能,而在使用过程中常常会有一些迷惑的地方,做一个杂记,总结一下。

启用缓存后,客户端的请求流程

如上图所示,涵盖了一个请求在使用缓存时的大致流程,不过有一些细节需要补充:

  1. 不仅仅是服务器可以在response里添加Cache-Control头部,request的头部也可以出现Cache-Control,比如当我们强制刷新浏览器,会有Cache-Control: no-store。所以请求头里的Cache-Control会影响上图的流程,作以下补充:在判断是否有本地缓存前,如果Cache-Control的值为no-store表示,不管有没有缓存都去重新请求资源;在判断是否过期之前,如果Cache-Control的值为no-cache,表示不管缓存是否过期都去服务器验证,即带上If-None-Match或者If-Modified-Since头部;在缓存没过期取本地缓存之前,如果Cache-Control的值为max-age=0,那么仍然会去服务器验证。
  2. 当我们使用本地缓存时,status code会显示200(from cache),区别于304(from cache)(协商缓存),前者并没有真正的发送请求。

Cache-Control & Expires

这两个响应头部都可以表示资源缓存的过期时间,当仅存在Expires时,浏览器会根据请求的Date和Expires比较判断缓存是否过期,当二者同时存在时,后者会被忽略。

Etag & Last Modified

这两个响应头部都可以作为资源变更的校验信息,不同的是,Etag是一种强校验器,以apache为例,由资源内容的hash,资源最后修改的时间戳,以及资源对应文件系统的inode生成,格式为x-x-x,但这不是绝对的生成方法,比如nginx是以最后修改的时间戳和资源内容长度生成。使用Etag不但可以高效的利用缓存还可以配合If-None-Match头部防止“空中碰撞”。而Last Modified头部可以理解成弱校验器,因为它只验证了最后修改时间这一项条件,通常情况下,最后修改时间是一种很有效的验证方式,但是有一些例外的场景:1. 客户端时间和服务器时间标准不统一。2. 如果同一秒内某个资源被修改了两次,那么可能最后一次修改不会返回给浏览器(通常我们都会将etag的选项打开)。

If-None-Match & If-Modified-Since

这两个请求头都是要求服务器做资源检验使用,后者表示如果请求的资源在对应的时间之后为修改过,那么将返回304,只能用于GET/HEAD请求,前者表示如果请求的资源的Etag与给定Etag相同时返回304,可以在更新资源时使用比如PUT/POST。

当这两个请求头部同时存在时,以nginx为例,(可能还有If-Match,If-Unmodified-Since头部,同时nginx还会有一个if-modified-since指令)会依次比较If-Unmodified-Since -> If-Match -> If-Modified-Since -> If-Not-Match。满足一个200条件都会重新获取资源。

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注