前端静态资源的缓存和更新问题解析

时间:2024-03-11 09:31:35

浏览器缓存主要有两类 
缓存协商:Last-midified ,Etag 
彻底缓存:cache-control,Expires 

  缓存协商的意思是需要去服务器端询问页面有没有修改过,没有修改过则返回304直接使用缓存内容,否则返回新内容 
协商步骤: 

1、服务器发送带Last-midified:GMTtime 头的http response

2、浏览器下次请求时带上if-modified-since:GMTtime http 请求头

3、服务端用本地Last-midified时间与if-modified-since比较,计算浏览器数据是否过期并发送响应

Etag的工作原理与Last-midified类似,不同点在于Etag的值是用户可自定义的 

  彻底缓存的意思是在缓存失效之前不再需要跟服务器交互

常用的是Expires,Expires的值是一个绝对时间,由服务器产生 这儿存在一个问题,就是服务器的时间可能给客户端的时间不一致导致缓存时间的偏差

要解决这个问题就要使用cache-control,它保存的是一个相对浏览器的时间

如果同时存在cache-control和Expires怎么办呢? 浏览器总是优先使用cache-control,如果没有cache-control才考虑Expires 

expire:
如果apache开启了expire模块, 当浏览器发送该资源请求的时候, apache返回资源的同时,会返回一个名为expire的http头,expire头的内容是一个时间值, 这一个值就是资源在本地的过期时间, 这个值会存在本地.
也就是说,在本地缓存阶段,在本地找到了一个对应的资源值,而且当前时间还没超过资源的过期时间, 那么就直接使用这一个资源,不会发送http请求.

cache-control:
cache-control是http协议中常用的头部之一,顾名思义, 他是负责控制页面的缓存机制,如果该头部指示缓存, 缓存的内容也会存在本地, 操作流程和expire相似,但也有不同的地方, cache-control有更多的选项, 而且也有更多的处理方式.

if-modified-since 和 last-modified:
当apache接收到一个资源请求(假设是用户是第一次访问,没有任何缓存), 服务器返回资源的同时,还会发送一个last-modified的http响应头, last-modified响应头的内容值是该资源在服务器上最后修改的时间.浏览器接受到这个http头后,会
把其内容值和资源同时保存起来.
当用户第二发送资源请求(假设这里expire没有生效或者已经过期), 浏览器在本地找到了一个相同的资源,但是不能确定该资源是否和服务器上的一样(有可能在两次访问期间,服务器上的资源已经被修改过),此时浏览器发送请求的时候,请求头内会
附带一个if-modified-since的请求头, 这个头部的内容就是上一次last-modified返回的值, 服务器把这个头的值和请求资源的最后修改时间对比,如果两个值相同,则认为资源没有修改,将会返回304,让浏览器使用本地资源.否则服务器将返回资源,而且
返回200状态

if-none-match 和 etag:
其实这两个头部和if-modified-since, last-modified的工作原理是一样的, if-none-match作为请求头, etag作为响应头.既然工作原理一样, 为什么etag这对头部会出现呢?
原因在于, last-modified请求头的内容是以文件最后修改的时间作为对比的,但是unix系统里面, 文件修改的时间只保存到了秒. 如果某些应用内存在1秒内对文件做了多次修改,这样last-modified是不能完成比较功能的.所以要引入一个新的机制(原因可能不止这一个);
etag的值一般由3个数值组成,资源的inode值, 最后修改时间, 资源大小,以16进制组成一个字符串, 例如:1a-182b-10f; 但这个格式不是固定的, 只要保证该值的唯一性,但不限格式.

静态资源的更新:张云龙老师的blog写的很好移步这里

 

html5离线存储

步骤:

1、配置apache让apache支持manifest文件

2、创建manifest文件test.manifest

1 CACHE MANIFEST  # wanz app v1     
2 # 指明缓存入口(指明需要缓存的文件)  
3 CACHE:  index.html  style.css  images/logo.png  scripts/main.js     # 以下资源必须在线访问  
4 NETWORK:  login.php     
5 # 如果index.php无法访问则用404.html代替  
6 FALLBACK:  /index.php /404.html

3、关联manifest文件到html文档

 1 <html manifest="test.manifest"> ... </html> 

注意:#是用来注释一行的,但它还有一个小作用,web应用的缓存只有在manifest文件被修改的情况下才会被更新,所以如果你只是修改了被缓存的文件,那么用户本地的缓存还是不会被更新的,但是你可以通过修改manifest文件来告诉浏览器需要更新缓存了。利用这点,你可以像上面的例子中那样,写一句这样的注释一个文件版本:

# wanz app v1

优点:你可以很明确的了解离线web应用的版本
   通过简单的修改这个版本号就可以轻易的通知浏览器更新
   你可以配合JavaScript程序来完成缓存更新

CACHE:
这个是manifest文件的默认入口,在此入口之后罗列的文件 (或直接写在CACHE MANIFEST后的文件)在它们下载到本地后会被缓存起来
NETWORK:
可选的,在此节后面所罗列的文件是需要访问网络的,即使用户离线访问了也会直接跳过缓存而访问服务器
FALLBACK:
可选的,用来指定资源无法访问时的回调页面。每一行包括两个URI,第一个是资源文件URI,第二个是回调页面URI。

html5缓存的更新问题:

方法有三种:

1、用户清除了离线存储的数据,这个不一定就是清理浏览器历史记录就可以做到的,因为不同浏览器管理离线存储的方式不同。比如Firefox的离线存储数据要到“选项”=>“高级”=>“网络”=>“脱机存储”里才可以清除。
2、manifest文件被修改,上面说的,你修改了manifest文件里所罗列的文件也不会更新缓存,而是要替换manifest文件//修改注释更新# wanz app v1
3、使用JavaScript api编写更新程序

方法12为自动更新,方法3为手动更新

1 var appCache = window.applicationCache;     
2 appCache.update(); // 开始更新     
3 if (appCache.status == window.applicationCache.UPDATEREADY) {    
  appCache.swapCache(); // 得到最新版本缓存列表,并且成功下载资源,更新缓存到最新
}