Blog icon indicating copy to clipboard operation
Blog copied to clipboard

HTTP缓存

Open shenxuxiang opened this issue 6 years ago • 0 comments

HTTP 缓存机制

我们认为浏览器存在一个缓存的数据库,用来存储一些不经常变化的静态文件(img,css,js文件等),一般将缓存分为强制缓存和协商缓存。强制缓存和协商缓存可以同时存在,且强制缓存的优先级大于协商缓存。

强制缓存

如果缓存数据库中已经存在所请求的数据,那么直接从缓存数据库中去获取数据,当缓存数据库中没有所请求的的数据,

强缓存还有两种区分

  • from memory cache: 表示从内存中读取的缓存,这种缓存在页面关闭以后缓存就不存了,下次重新打开页面的时候会再次请求
  • from disk cache: 表示从硬盘中读取的缓存,这种缓存不会随中页面关闭而失效(cache-control|expires有关),页面再次打开的时候直接从disk中获取

协商缓存

客户端会先去缓存数据库中去获取缓存数据的标识,然后一起发送给服务端,服务端会去验证缓存是否已经失效,如果失效就重新返回新的数据,否则就返回304,客户端直接去缓存数据库中获取数据。

如何判断缓存是否失效

我们可以从服务端返回的 response header 部分的某些字段来判断

  • Cache-Control
  • Expires
  • Last-Modified
  • Etag

强制缓存主要用到的是 Expires、Cache-Contro

Expires
它的值是服务器返回的数据有效到期时间,当再次请求时的时间在这个时间以内,那么直接使用缓存。但是服务器时间和客户端时间是有误差的,而且 `Expires` 是http1.0的产物,所以一般使用Cache-Control代替。
Cache-Control 有很多的属性
  • private: 客户端可以缓存
  • public: 客户端和服务端都可以缓存
  • max-age: 缓存将在给的多少秒以后失效
  • no-cache: 使用协商缓存
  • no-store: 不缓存

协商缓存主要用到的是 ETag,Last-Modifide (将其值作为缓存数据的标识的值,发送给服务器去验证)

Last-Modified: 资源最后一次修改的时间

如果一个资源被修改了,但是他的内容却没有发生变化 Last-Modified也会发生改变

  • if-modified-since 作为缓存数据的标识,发送给服务器进行验证
  • 当浏览器再次请求的时候会将if-modified-since字段放在请求头里面,服务端接收到请求以后会去比较if-modified-since 和所请求的资源的最后一次修改时间对比,如果一致返回304,否则就返回新的资源。
Etag 服务器返回的,表示当前资源在服务器生成的唯一标识

ETag的计算是通过计算方法得出来的,算法会占用一定的资源,每一次资源发生变化以后就会重新生成ETag。所以一般很少使用ETag

  • if-none-match 作为缓存数据的标识,发送给服务器进行验证
  • 当浏览器再次请求的时候会将if-none-match放在请求头里面,服务端接收到请求以后会去比较if-none-match和当前所请求的资源的ETag标识对比,如果一致的话就返回304,否则就重新返回资源
如何计算ETag

服务器根据文件的一些信息会计算出ETag: * 文件的索引节 inode * 最后一次修改时间 mtime 和大小 size

Nginx官方默认的ETag计算方式是为文件最后修改时间16进制-文件长度16进制。例:ETag: “59e72c84-2404”

自定义:

	// 这里额stat是通过nodejs的 fs.statSync 或者 fs.stats发放读取到的文件信息
	function stattag (stat) { 
		var mtime = stat.mtime.getTime().toString(16); 
		var size = stat.size.toString(16);
		return '"' + size + '-' + mtime + '"';
	}
ETaglast-modified 的优先级
* 如果缓存的资源中两者都有的话,就将两者一起发送给服务器;服务器在判断时会会先判断ETag
如果 `if-non-match` 和 `ETag` 不一样那么重新返回资源 `status=200`,否则就返回304;这个时候不会再去判断 `last-modified`。

* 只存在 `last-modified` :如果 `if-modified-since` 和 `last-modified` 不一样,那么就重新返回资源 `status=200` 否则返回304。
Last-Modified,If-Modified-SinceETag、If-None-Match 一般都是同时启用,这是为了处理Last-Modified不可靠的情况。有一种场景需 要注意:
* 分布式系统里多台机器间文件的 `Last-Modified` 必须保持一致,以免负载均衡到不同机器导致比对失败;
* 分布式系统尽量关闭掉ETag(每台机器生成的ETag都会不一样);

使用缓存的优点

* 减少不必要的请求,减轻服务器的压力,提升网站的性能
* 加快客户端网页加载的速度

最后

关于js,css等文件需要更新,但是设置的缓存时间比较长怎么办???

  • 改变js,css等文件的请求url,就会重新请求。所以我们一般可以加上各种查询参数,改变url就好了
  • 实际开发中,我们在webpack打包的时候给js,css等文件的文件名加上hash值,每次打包hash值都是不一样的,这样就改变了url。

shenxuxiang avatar Apr 24 '19 10:04 shenxuxiang