通过HTTP Header控制缓存

通过HTTP Header控制缓存,第1张

我们经常通过缓存技术来加快网站的访问速度,从而提升用户体验。HTTP协议中也规定了一些和缓存相关的Header,来允许浏览器或共享高速缓存缓存资源。这些Header包括:

Last-Modified 和 If-Modified-Since

ETag 和 If-None-Match

Expires

Cache-Control

以上Header又可以分成两种类型:

协商缓存:浏览器发送验证到服务器,由服务器决定是否从缓存中读取,如 1 和 2 。

强缓存:浏览器验证缓存的有效性,然后决定是否从缓存中读取数据,如 3 和 4 。

本文将会分别介绍这四种配置的作用以及可能产生的影响。

1、Last-Modified 和 If-Modified-Since

Last-Modified:服务器在响应请求时,告知浏览器资源的最后修改时间。

If-Modified-Since:浏览器再次发送请求时,会通过此Header通知服务器在上次请求时所得到的资源最后修改时间。服务器会将If-Modified-Since与被请求资源的最后修改时间进行比对。若资源的最后修改时间晚于If-Modified-Since,表示资源已被改动,则响最新的资源,返回200状态码;若资源的最后修改时间早于或等于If-Modified-Since,表示浏览器端的资源已经是最新版本,响应304状态码,通知浏览器继续使用缓存中的资源。

2、ETag 和 If-None-Match

ETag:服务器分配给资源的唯一标识符,资源被修改后,ETag也会随之发生变化。

If-None-Match:浏览器再次发送请求时,会通过此Header通知服务器已缓存资源的ETag。服务器会将If-None-Match与被请求资源的最新ETag进行比对。若不相同,表示资源已被改动,则响应最新的资源,返回200状态码;若值相同,则直接响应304状态码,通知浏览器继续使用缓存中的资源。

 3、Expires

服务器可以通过此Header向浏览器传递一个具体的时间(格林威治格式,例如:Thu, 19 Jul 2018 07:43:05 GMT) ,来明确地宣告资源的有效期。在资源过期之前,浏览器不再发送请求,而是直接从缓存中读取数据。只有当资源过期之后,浏览器才会再次向服务器请求该资源。

4、Cache-Control

服务器使用此Header来向客户端建议缓存策略,它有一下几个可选值:

max-age=秒:告知浏览器缓存的有效时长,在该时间内浏览器将直接从缓存中读取数据。

s-maxage=秒:作用同max-age,但是只对共享高速缓存(如CDN)有效,对浏览器无效。

no-cache:告知浏览器不要直接使用缓存,而是必须向服务器发送请求。

no-store:告知浏览器不要缓存本次请求和响应的任何信息。

public:宣告任何缓存媒介都可以缓存该响应。

private:宣告该响应只允许个体客户端(如浏览器)去缓存,而不允许共享高速缓存(如CDN)去缓存。

在上面的介绍中我们了解到浏览器会根据max-age设置的时间进行缓存。而通过研究发现CDN也会识别源站响应头中Cache-Control属性,根据max-age设置的时间进行缓存,但是,如果源站同时设置了s-maxage和max-age,那么CDN会优先采用s-maxage。

下面通过图例来展示一下这些可选值的效果。

首先了解一下浏览器是怎样根据max-age进行缓存的:

从上图不难发现,服务器在Header中返回了Cache-Control: max-age=100后,浏览器成功缓存100秒,该时间段内的请求都从直接以本地缓存来响应。

那么,服务器在Header中返回Cache-Control:s-maxage=100时,又会对浏览器产生什么样的影响呢?

如上图所示,浏览器没有采取任何缓存策略,这是因为s-maxage面向的是共享高速缓。

上面这两个例子很容易理解,在现实世界中,为了加快网站响应速度,我们可能会在浏览器和服务器之间引入CDN服务。浏览器的请求会先到达CDN,然后CDN判断是从缓存中读取数据还是回源到服务器。接下来,让我们看看max-age和s-maxage会对CDN的缓存策略带来哪些影响。

可以看出CDN也会利用max-age来缓存,所以在100秒内强制刷新浏览器时,CDN会直接用缓存来响应。

如果服务器使用了s-maxage又会如何呢?

不难发现CDN对max-age和s-maxage采取了同样的缓存策略,但浏览器并不会根据s-maxage来进行缓存。

CDN供应商的特殊规则

我们分别测试了阿里云和腾讯云的CDN对Cache-Control的支持情况,发现他们都有一些独特的规则。阿里云CDN可以在控制台里设置Cache-Control,该设置会覆盖源服务器的Cache-Control。

腾讯云CDN虽然没有再控制台提供覆盖Cache-Control的功能,但其规则却一点也不简单,在使用的时候一定要特别注意:

服务器和CDN均不对缓存进行配置时,CDN会采用默认的缓存机制(静态文件缓存30天,动态请求不缓存);

CDN配置缓存机制(但并未开启高级缓存配置)且服务器设置Cache-Control: s-maxage=200,max-age=100时,CDN会按照其控制台设置的规则进行缓存,浏览器则按照max-age进行缓存;

服务器不设置Cache-Control时,CDN会自动在响应的Header中添加Cache-Control: max-age=600,这就会让浏览器将该资源缓存600秒;

服务器设置为禁用缓存时,CDN和浏览器均不进行缓存;

服务器设置Cache-Control: s-maxage=200,max-age=100并开启CDN的高级缓存配置时,CDN会从s-maxage和控制台中设置的缓存时间中选择最小值来作为缓存时间,而浏览器则始终使用max-age;

服务器设置Cache-Control:max-age=100并开启CDN的高级缓存配置时,CDN会从max-age和控制台中设置的缓存时间中选择最小值来作为缓存时间,不影响浏览器的缓存策略。

 组合使用

如果同时设置了这些Header,浏览器和高速共享缓存会按照下面的优先级进行缓存:

Cache-Control >Expires >ETag >Last-Modified

也就是说,Cache-Control不仅是强缓存,而且拥有最高的优先级,我们可以为不经常发生变化的资源应用该Header来提升响应时间。

 在Ada中使用缓存

Ada提供了UI脚手架和API脚手架,这两类脚手架的服务器端入口文件分别为index.server.js和index.js,我们只需要在入口文件的请求处理函数中为响应添加适当的Header,即可通知客户端进行响应的缓存,比如:

// 设置CDN缓存300秒,浏览器缓存200秒 ctx.response.headers.set('Cache-Control',public,s-maxage=300,max-age=200)

在为请求添加缓存Header之前,应该先为其制定适当的缓存策略,需要考虑该URL是否适合缓存(数据是否特定于用户)以及需要缓存的时长等等。

总结

通过使用这些HTTP Header,我们可以主动影响浏览器甚至CDN的缓存策略,从而减少请求数量,提升网页性能,减轻服务器压力。

Ada的灵活机制能让我们为不同的URL设置不同的缓存策略,能够更有针对性地进行主动缓存。

expires 指令可以控制 HTTP 应答中的“Expires ”和“ Cache-Control ”的头标(起到控制页面缓存的作用)

语法:expires [time|epoch|max|pff]默认值:offexpires指令控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息,启动控制页面缓存的作用time:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。time值还控制"Cache-Control"的值:负数表示no-cache正数或零表示max-age=time epoch:指定“Expires”的值为 1January,1970,00:00:01 GMTmax:指定“Expires”的值为31December2037 23:59:59GMT,"Cache-Control"的值为10年。-1:指定“Expires”的值为当前服务器时间-1s,即永远过期。off:不修改“Expires”和"Cache-Control"的值

expires使用了特定的时间,并且要求服务器和客户端的是中严格同步。

而Cache-Control是用max-age指令指定组件被缓存多久。

对于不支持http1.1的浏览器,还是需要expires来控制。所以最好能指定两个响应头。但HTTP规范规定max-age指令将重写expires头。

如果不想让代理或浏览器缓存,加no-cache参数或private参数:

# expires 1d

add_header Cache-Control no-cache

add_header Cache-Control private

这样浏览器F5刷新时,返回的依然是200,而不是304.

记录一个nginx控制缓存的例子:

expires 1d

add_header Cache-Control no-cache

add_header Cache-Control private

if ( !-e $request_filename) {

rewrite ^(.*) http://test.zhaopin.com/index.html break

# add_header Cache-Control no-cache

# add_header Cache-Control private

当我将add_header写在rewrite之后时,发现add_header竟然不起作用了。。是因为写进了if里面..

apache的mod_expires模块使得在使用expires头时能像max-age那样以相对的方式设置日期,通过ExpiresDefault指令完成。例如:图片等过期时间为请求开始的10年之后

<FileMatch"\.(gif|jpg|js|css)$">

ExpiresDefault "access plus 10years"

</FileMatch>

它像响应中发送Expires头和Cache-Control max-age头。

expires|etag控制页面缓存区别expires:像上面文章提到的:expires指令控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息,启动控制页面缓存的作用time:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。time值还控制"Cache-Control"的值:负数表示no-cache正数或零表示max-age=time epoch:指定“Expires”的值为 1January,1970,00:00:01 GMTmax:指定“Expires”的值为31December203723:59:59GMT,"Cache-Control"的值为10年。-1:指定“Expires”的值为当前服务器时间-1s,即永远过期。off:不修改“Expires”和"Cache-Control"的值

expires使用了特定的时间,并且要求服务器和客户端的是中严格同步。

而Cache-Control是用max-age指令指定组件被缓存多久。

对于不支持http1.1的浏览器,还是需要expires来控制。所以最好能指定两个响应头。但HTTP规范规定max-age指令将重写expires头。一般用于页面变化不是很快的时候,如果缓存过期了,浏览器在重用它之前会首先确认他是否有效,就是一个“条件GET请求”,如果有效,返回304状态码。expires通过Last-Modified响应头来确定。

这时返回的状态码是304,而在请求中比第一次多了If-Modified-Since头,和原始服务器中的Last-Modified制作比较,所以实现浏览器缓存并判断是否过期。

简单的说,Last-Modified 与If-Modified-Since 都是用于记录页面最后修改时间的 HTTP 头信息,只是Last-Modified 是由服务器往客户端发送的 HTTP 头,而 If-Modified-Since则是由客户端往服务器发送的头,可以看到,再次请求本地存在的 cache 页面时,客户端会通过 If-Modified-Since头将先前服务器端发过来的 Last-Modified最后修改时间戳发送回去,这是为了让服务器端进行验证,通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回新的内容,如果是最新的,则返回304告诉客户端其本地cache的页面是最新的,于是客户端就可以直接从本地加载页面了,这样在网络上传输的数据就会大大减少,同时也减轻了服务器的负担。

如果不想让代理或浏览器缓存,加no-cache参数或private参数:

# expires 1d

add_header Cache-Control no-cache

add_header Cache-Control private

etag:实体标签,是用来确认web服务器和浏览器缓存有效性的一种机制。原始服务器使用ETag响应头来指定组件的ETag浏览器通过If-None-Match头将ETag传回原始服务器。如果匹配,返回304

依然返回的状态码是304,而在请求中比第一次多了If-None-Match头。所以实现浏览器缓存。如果这个值对不上,则缓存过期。

ETags和If-None-Match是一种常用的判断资源是否改变的方法。类似于Last-Modified和HTTP-If-Modified-Since。但是有所不同的是Last-Modified和HTTP-If-Modified-Since只判断资源的最后修改时间,而ETags和If-None-Match可以是资源任何的任何属性。

ETags和If-None-Match的工作原理是在HTTPResponse中添加ETags信息。当客户端再次请求该资源时,将在HTTPRequest中加入If-None-Match信息(ETags的值)。如果服务器验证资源的ETags没有改变(该资源没有改变),将返回一个304状态;否则,服务器将返回200状态,并返回该资源和新的ETags。

IIS上的ETag格式需要修改。

主要看response headers中Cache-Control的值

Cache-Control取值含义:

private:仅浏览器可以缓存

public:浏览器和代理服务器都可以缓存

max-age=xxx 过期时间(秒)

no-cache:不进行强缓存

no-store:不强缓存也不协商缓存

触发条件:

1、Cache-Control的值为no-cache(不强缓存)

2、max-age 设置的时间导致文件过期了

ETag:每个文件都有一个,改动文件就会变(类似md5)

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符。

Last-Modified:文件修改时间

每次http返回来response headers中都会带ETag和Last-Modefied ,下次请求时在request header就把这两个给带上但是名字有了变化(ETag->If-None-Match,Last-Modified->If-Modified-Since),服务端把带过来的标识与之前的标识进行对比 判断是否更改过了

请求资源时,把用户本地该资源的 ETag 同时带到服务端,服务端和最新资源做对比。

如果资源没更改,返回304,浏览器读取本地缓存。

如果资源有更改,返回200,返回最新的资源。

1.从服务器获取新的资源

2.命中强缓存,且资源没过期,直接读取本地缓存(请求成功 文件大小size会显示 from disk cache)

3.命中协商缓存,且资源未更改,读取本地缓存。

注意:协商缓存无论如果,都要向服务端发请求的,只不过,资源未更改时,返回的只是header信息,所以size很小;而资源有更改时,还要返回body数据,所以size会大。

可以有后端服务器配置,也可以在nginx中配置

参考链接: https://blog.csdn.net/Amnesiac666/article/details/121101165

疑问1:max-age时间是怎么来的 从什么时候开始计时

疑问2:为什么是response header中的而不是request header中


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/6363714.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-21
下一篇 2023-03-21

发表评论

登录后才能评论

评论列表(0条)

保存