要:添加Expires头能有效的利用浏览器的缓存能力来改善页面的性能,能在后续的页面中有效避免不少没必要要的Http请求,WEB服务器使用Expires头来告诉Web客户端它可使用一个组件的当前副本,直到指定的时间为止。javascript
例如:Expires:Thu,15 Apr 2010 20:00:00 GMT; 他告诉浏览器缓存有效性持续到2010年4月15日为止,在这个时间以内相同的请求使用缓存,这个时间以外使用http请求。html
Cathe-Control:max-age=315360000java
Expires有一个很是大的缺陷,它使用一个固定的时间,要求服务器与客户端的时钟保持严格的同步,而且这一天到来后,服务器还得从新设定新的时间。node
HTTP1.1引入了Cathe-Control,它使用max-age指定组件被缓存多久,从请求开始在max-age时间内浏览器使用缓存,以外的使用请求,这样就能够消除Expires的限制,浏览器
若是对浏览器兼容性要求很高的话,能够两个都使用。缓存
这里对http 304 状态结合max-age作一个总结:服务器
浏览器初次访问服务器---------------服务器返回200状态工具
以下图:性能
浏览器再次请求服务器时,浏览器会先判断max-age,若是到期则直接请求服务器,不然直接从缓存中取,ui
服务器收到请求后,判断文件是否被修改过,如果则直接返回200,不然返回304,浏览器将从缓存中获取文件。
若同步刷新页面,则浏览器并不会先判断max-age,而是直接发送请求,服务器接收到请求后,判断文件是否有变化,如有则返回200,若没有则返回304
修订文件名
浏览器利用max-age取出缓存有很大的缺陷,若是在max-age时间内,服务器文件有修改,这样用户就不能第一时间获取最新的信息,所以这里最有效的方法是修改请求的文件名。
但为了确保用户能获取组件最新版本,须要在整个项目中修改组件的文件名,这取决于你的html页面,这项工做可能很轻松也可能很痛苦,
今天在群里聊天。说道了Expires。这里来讲明下这两个的区别吧。
1.概念
Cache-control 用于控制HTTP缓存(在HTTP/1.0中可能部分没实现,仅仅实现了 Pragma: no-cache)
Expires 表示存在时间,容许客户端在这个时间以前不去检查(发请求),等同max-age的效果。可是若是同时存在,则被Cache-Control的max-age覆盖。
Cache-Control 的含义
可缓存性
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 没过时,能够继续使用缓存资源,不须要从新请求。浏览器主动设置这个头,只有在发起端才有用。
从新验证
must-revalidate,浏览器可能会用到,若是 max-age 过时,须要从新发送请求,获取这部分数据,再来验证数据是否真的过时,而不能直接使用本地缓存。
proxy-revalidate,用在缓存服务器中,指定缓存服务器过时后,必须向源服务器从新请求,不能直接使用本地缓存。
其余
no-store,本地和代理服务器都不能够存储缓存,每次都要从新请求,拿到内容。
no-transform,主要是用在 proxy 服务器,不容许进行格式转换。
Cache-Control 的使用
浏览器缓存
经过 Cache-Control 以及 max-age 设置,达到长缓存的效果。
启动服务器 node server.js,在 localhost:8888 打开,查看network,当设置 max-age 后,刷新页面,浏览器直接从缓存中进行读取,不去要再向服务器请求,达到缓存静态资源的目的。
存在的问题,服务端修改返回内容,客户端没有加载新的内容,由于请求 url 没变,浏览器会直接从缓存读取,不须要通过服务端验证,致使静态资源更新后,没有及时更新到客户端。
解决方案,打包静态资源时,根据内容进行 hash 计算,生成文件名的 hash 码。内容变,hash 码变,请求资源 url 变,浏览器从新请求加载资源,达到更新缓存的目的。
// server.js const http = require('http') const fs = require('fs') http.createServer(function (request, response) { console.log('request come', request.url) if (request.url === '/') { const html = fs.readFileSync('test.html', 'utf8') response.writeHead(200, { 'Content-Type': 'text/html' }) response.end(html) } if (request.url === '/script.js') { response.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=200' // 浏览器缓存时间 }) response.end('console.log("script loaded twice")') } }).listen(8888) console.log('server listening on 8888')
max-age能够接收不少值,如 ‘Cache-Control’: ‘max-age=200, public’
缓存验证Last-Modified和Etag的使用
资源验证
验证头
Last-Modified
Etag
Last-Modified
上次修改时间。
配合If-Modified-Since或If-Unmodified-Since使用,一般浏览器使用前者。
服务器对比上次修改时间以验证资源是否须要更新。
Etag
数据签名,资源内容会对应有一个惟一的签名,若是资源数据更改,签名也会变。
配合If-Match或者If-None-Match使用,其值就是服务端返回的 Etag 值
对比资源的签名判断是否使用缓存
验证头的使用
服务器设置 Last-Modifed 和 Etag 的值,浏览器请求会携带这两个头,在请求头中,会有 If-Modified-since: Last-Modifed值 和 If-None-Match: Etag值。
这时 response 中是有内容的,这里但愿服务器不返回实际的内容,只须要告诉浏览器直接读取缓存便可。经过在服务器端进行判断。
这时查看 respones 发现仍是有内容,这个内容是 Chrome 浏览器 从缓存中读取显示出来的,服务器没有返回内容。
如何判断服务端经过验证,可是从缓存读取的呢,经过服务器设置 HTTP Code 304,Not Modified 表示资源没有修改,直接读缓存,这时就会忽略服务端返回的内容。
Chrome 浏览器 控制台 勾上 Disable cache,刷新页面,发送的请求中就不包括和缓存相关的头了
// server.js const http = require('http') const fs = require('fs') http.createServer(function (request, response) { console.log('request come', request.url) if (request.url === '/') { const html = fs.readFileSync('test.html', 'utf8') response.writeHead(200, { 'Content-Type': 'text/html' }) response.end(html) } if (request.url === '/script.js') { console.log(request.headers) const etag = request.headers['if-none-match'] if(etag === '777') { response.writeHead(304, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=2000000, no-cache', 'Last-Modified': '123', 'Etag': '777' }) response.end('') // 这里不传任何内容,即便有内容,浏览器也不会读取 } else { response.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=2000000, no-cache', // 经过 no-cache,即便没过时浏览器也要向服务器验证,不会从缓存读取。 'Last-Modified': '123', // 随便设的值 'Etag': '777' }) response.end('console.log("script loaded twice")') } } }).listen(8888) console.log('server listening on 8888')
no-cache
不从缓存读取
'Cache-Control': 'max-age=2000000, no-cache', // 经过 no-cache,即便没过时浏览器也要向服务器验证,不会从缓存读取。
no-store
设置 no-store,即便服务器下发了缓存相关头,浏览器也会忽略任何和缓存相关的信息,发送请求不会携带相关头,直接去请求最新的数据。
Chrome浏览器->右上角->更多工具->清理浏览器缓存
'Cache-Control': 'max-age=2000000, no-store'