http缓存(原理、机制、配置)

http缓存机制

背景

http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,若是浏览器有“要请求资源”的副本,就能够直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。node

常见的http缓存只能缓存get请求响应的资源,对于其余类型的响应则无能为力,因此后续说的请求缓存都是指GET请求。nginx

http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接200,不然就把请求参数加到request header头中传给服务器,看是否命中协商缓存,命中则返回304,不然服务器会返回新的资源。segmentfault

强缓存

浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息),若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通讯。
状态码为200浏览器

Expires

Expires是http1.0的规范,它的值是一个绝对时间的GMT格式的时间字符串,这个时间表明这这个资源的失效时间,只要发送请求时间是在Expires以前,那么本地缓存始终有效,则在缓存中读取数据。失效的时间是一个绝对时间,当服务器与客户端时间误差较大时,会致使缓存混乱。若是同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。缓存

Cache-Control

Cache-Control是在http1.1中出现的,主要是利用该字段的max-age值来进行判断,它是一个相对时间,例如Cache-Control:max-age=3600,表明着资源的有效期是3600秒。cache-control除了该字段外,还有下面几个比较经常使用的设置值:服务器

类型 描述
public 客户端和代理服务器均可以缓存该资源;客户端在xxx秒的有效期内,若是有请求该资源的需求的话就直接读取缓存,status code:200 ,若是用户作了刷新操做,就向服务器发起http请求
private 只让客户端能够缓存该资源,代理服务器不缓存;客户端在xxx秒内直接读取缓存,status code:200
immutable 客户端在xxx秒的有效期内,若是有请求该资源的需求的话就直接读取缓存,status code:200 ,即便用户作了刷新操做,也不向服务器发起http请求
no-cache 跳过设置强缓存,可是不妨碍设置协商缓存;通常若是你作了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端
no-store 不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了

协商缓存

若是没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Last-Modified/If-Modified-Since和Etag/If-None-Match),由服务器根据请求中的相关header信息来比对结果是否协商缓存命中;若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,可是并不返回资源内容,它会告知浏览器能够直接从缓存获取;不然返回最新的资源内容。
状态码为304编码

last-modified

last-modified记录资源最后修改的时间。启用强缓存后,请求资源以后的响应头会增长一个last-modified字段,当再次请求该资源时,请求头中会带有if-modified-since字段,值是以前返回的last-modified的值。服务端会对比该字段和资源的最后修改时间,若一致则证实没有被修改,告知浏览器可直接使用缓存并返回 304;若不一致则直接返回修改后的资源,并修改last-modified为新的值。spa

last-modified 有如下两个缺点:代理

  • 只要编辑了,无论内容是否真的有改变,都会以这最后修改的时间做为判断依据,当成新资源返回,从而致使了不必的请求响应,而这正是缓存原本的做用即避免不必的请求。
  • 时间的精确度只能到秒,若是在一秒内的修改是检测不到更新的,仍会告知浏览器使用旧的缓存。

etag

为了解决 last-modified 上述问题,有了 etagetag 会基于资源的内容编码生成一串惟一的标识字符串,只要内容不一样,就会生成不一样的 etag。启用 etag 以后,请求资源后的响应返回会增长一个 etag 字段,当再次请求该资源时,请求头会带有if-no-match字段,值是以前返回的etag值,服务端会根据该资源当前的内容生成对应的标识字符串和该字段进行对比,若一致则表明未改变可直接使用本地缓存并返回 304;若不一致则返回新的资源(状态码200)并修改返回的 etag 字段为新的值。code

能够看出 etaglast-modified 更加精准地感知了变化,因此 etag 优先级也更高。不过从上面也能够看出 etag 存在的问题,就是每次生成标识字符串会增长服务器的开销。因此要如何使用 last-modifiedetag 还须要根据具体需求进行权衡。

机制

clipboard.png

一、用户发起了一个http请求后,浏览器显示经过强缓存机制检测浏览器中该资源是否有缓存,有则直接返回资源,状态码为200,而且不会请求服务器。
二、假若强缓存失效后,浏览器会向服务器请求资源,服务器会根据浏览器带过来的请求头信息进行协商缓存的检测,若协商缓存有效则直接返回资源,状态码为304.
三、当协商缓存也失效后,服务器从新获取资源返回给浏览器,状态码为200。

如何设置缓存

node等服务端设置

res.setHeader('max-age': '3600 public')  
res.setHeader(etag: '5c20abbd-e2e8')  
res.setHeader('last-modified': Mon, 24 Dec 2018 09:49:49 GMT)

nginx设置

image.png

本文参考:
http://www.noobyard.com/article/p-znpilvfv-w.html
https://www.jianshu.com/p/9c95db596df5