可缓存性
public :
http 请求返回的过程当中,在 cache-control 中设置这个值,代表 http 请求返回的内容所经过的任何路径当中(包括中间一些http代理服务器以及发出请求的客户端浏览器),都可以对返回内容进行缓存操作。
private:
代表只有发起请求的浏览器才可以进行缓存
no-cache:
可以在本地进行缓存,但每次发请求时,都要向服务器进行验证,如果服务器允许,才能使用本地缓存。
到期
max-age=,
缓存多少秒后过期,过期之后浏览器才会再次发送请求。
s-maxage=,
浏览器基本用不到,会代替 max-age,但只有在代理服务器中才会生效。在代理服务器中,如果都设置了 max-age,s-maxage,还是会读取 s-maxage。
max-stale=,
浏览器基本用不到,当 max-age 过期后,如果返回资源中有 max-stale 的设置。max-stale 是发起请求方主动携带的头,即使 max-age 过期,只要 max-stale 没过期,可以继续使用缓存资源,不需要重新请求。浏览器主动设置这个头,只有在发起端才有用。
Cache-Control 的使用
浏览器缓存
通过 Cache-Control 以及 max-age 设置,达到长缓存的效果。
启动服务器 node server.js,在 localhost:8888 打开,查看network,当设置 max-age 后,刷新页面,浏览器直接从缓存中进行读取,不去要再向服务器请求,达到缓存静态资源的目的。
存在的问题,服务端修改返回内容,客户端没有加载新的内容,因为请求 url 没变,浏览器会直接从缓存读取,不需要经过服务端验证,导致静态资源更新后,没有及时更新到客户端。
解决方案,打包静态资源时,根据内容进行 hash 计算,生成文件名的 hash 码。内容变,hash 码变,请求资源 url 变,浏览器重新请求加载资源,达到更新缓存的目的。
- 一般来说首页不设置缓存 尤其是html
- 一般给需要缓存的(如一些js和css)设置10年
response.setHeader('Cache-Control','max-age=300000000')
表示10年内,都不会再向服务器请求这个资源,那如果10年之内服务器要更新这个资源怎么办呢,在上图中说明,只有相同的URL,才会利用缓存,只要稍微让URL不一样,就可以了。
- 即尽量把一个版本缓存,能缓存多长时间就缓存多长时间,需要更新升级就改变其URL
expires
expires是cache-control没有出来之前用的技术,现在大部分都是用cache-control,cache-control是多长时间过期,expires是几分几秒过期(GMT时间),这个几分几秒过期指的是本地时间,万一用户的本地时间错乱,就会导致缓存也全部失效,所以比较不靠谱。两个都设置的话优先使用cache-control
Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记(HttpReponse Header)此文件在服务期端最后被修改的时间,格式类似这样:
Last-Modified:Tue, 24 Feb 2009 08:01:04 GMT
客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头(HttpRequest Header),询问该时间之后文件是否有被修改过:
If-Modified-Since:Tue, 24 Feb 2009 08:01:04 GMT
如果服务器端的资源没有变化,则自动返回HTTP304(NotChanged.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
注:如果If-Modified-Since的时间比服务器当前时间(当前的请求时间request_time)还晚,会认为是个非法请求
Etag
md5是一个摘要算法
let fileMd5 = md5(string)
response.setHeader('ETag', fileMd5)
这样请求的文件就会多一个响应头,叫ETag,下一次请求的时候,会把上次ETag的值放在请求头的if-None-Match里面,如果两个md5一样,就不需要下载,
if(request.headers['if-none-match'] === fileMd5) {
// 这样没有响应体,只有响应头
response.statusCode = 304
}
// 304状态码 NOT Modifiled 没改过
HTTP协议规格说明定义ETag为“被请求变量的实体标记”(参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式:
Etag:“5d8c72a5edda8d6a:3239″
客户端的查询更新格式是这样的:
If-None-Match:“5d8c72a5edda8d6a:3239″
如果ETag没改变,则返回状态304。
即:在客户端发出请求后,HttpReponse Header中包含Etag:“5d8c72a5edda8d6a:3239″
标识,等于告诉Client端,你拿到的这个的资源有表示ID:5d8c72a5edda8d6a:3239。当下次需要发Request索要同一个URI的时候,浏览器同时发出一个If-None-Match报头(Http RequestHeader)此时包头中信息包含上次访问得到的Etag:“5d8c72a5edda8d6a:3239″标识。
If-None-Match:“5d8c72a5edda8d6a:3239“
,这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果If-None-Match为False,不返回200,返回304(Not Modified) Response。