在前面的一篇文章中,我讨论了HTTP和它在这一点上的立场。这是一个将专门关于缓存。
作为用户,我们很容易因为缓冲视频,加载几秒钟的图片,由于内容正在加载而卡住的网页而感到沮丧。从一些缓存加载资源比从源服务器获取资源要快得多。它减少延迟,加速资源加载,减少服务器上的负载,降低带宽成本等。
介绍
什么是Web缓存?它是位于客户端和服务器之间的某处,持续查看请求及其响应,查找可以缓存的任何响应。以便在再次进行相同请求时消耗更少的时间。
注意,这个图像只是给你一个想法。根据缓存的类型,实现缓存的位置可能会有所不同。更多这一点。
在我们进一步详细介绍之前,让我在文章中进一步介绍将要使用的术语
- 客户端可以是您的浏览器或任何请求服务器获取某些资源的应用程序
- 原始服务器,真相的源,容纳客户端所需的所有内容,并负责满足客户端请求。
- Stale Content是缓存的但已过期的内容
- 新鲜内容是缓存中可用的尚未过期的内容
- 缓存验证是联系服务器以检查缓存内容的有效性并获得更新的过程,当它将要到期时
- 缓存无效化是删除缓存中可用的任何过时内容的过程
缓存位置
Web缓存可以是共享的或私有的,具体取决于它存在的位置。下面是缓存位置的列表
浏览器缓存
您可能已经注意到,当您单击浏览器中的后退按钮时,加载页面所需的时间比第一次加载时所需的时间少; 这是浏览器缓存中播放。浏览器缓存是缓存的最常见位置,浏览器通常为它保留一些空间。
浏览器缓存仅限于一个用户,与其他缓存不同,它可以存储“私有”响应。稍后再谈。
代理缓存
与为单个用户提供服务的浏览器缓存不同,代理缓存可以为访问相同内容的数百个不同用户提供服务。它们通常由ISP或任何其他独立实体在更广泛的层面上实施。
反向代理缓存
反向代理缓存或代理缓存在源服务器附近实现,以减少服务器上的负载。不同于由ISP等实现的代理缓存以减少网络中的带宽使用,代理或反向代理缓存由服务器管理员在源服务器附近实现以减少服务器上的负载。
虽然可以控制反向代理缓存(因为它是由您在服务器上实现的),您不能避免或控制浏览器和代理缓存。如果您的网站未配置为正确使用这些缓存,它仍将使用在这些缓存上设置的默认值进行缓存。
缓存标头
那么,我们如何控制Web缓存?每当服务器发出一些响应,它伴随着一些HTTP头,以指导缓存是否以及如何缓存此响应。内容提供者必须确保返回正确的HTTP头,以强制缓存如何缓存内容。
到期
在HTTP / 1.1和介绍之前Cache-Control
,有一个Expires
标题,它只是一个时间戳告诉缓存一些内容被认为是新鲜的时间。此标题的可能值是绝对到期日期; 其中日期必须为GMT。下面是示例头
Expires: Mon, 13 Mar 2017 12:22:00 GMT
应该注意的是,日期不能超过一年,如果日期格式错误,内容将被视为陈旧。此外,缓存上的时钟必须与服务器上的时钟同步,否则可能无法实现所需的结果。
虽然,Expires
头仍然有效并且被缓存广泛支持,应该优先考虑它的HTTP / 1.1后继Cache-Control
。
Pragma
另一个从老,前HTTP / 1.1天,是Pragma
。现在可以使用下面给出的缓存控制头来做一切。但是,我想指出的一点是,你可能会Pragma: no-cache
在这里和那里使用,希望阻止缓存的响应。它可能不一定工作; 因为HTTP规范在请求头中讨论它,并且在响应头中没有提及它。而Cache-Control
头应该用于控制缓存。
高速缓存控制
高速缓存控制指定内容被高速缓存的时间和方式。这个头文件系列是在HTTP / 1.1中引入的,以克服Expires
头文件的限制。
Cache-Control
头的值是复合的,即它可以有多个指令/值。让我们看看这个头可能包含的值。
私人的
设置缓存private
意味着内容不会被缓存在任何代理中,它只会被客户端(即浏览器)缓存,
Cache-Control: private
话虽如此,不要让它欺骗你,认为设置此标题将使您的数据安全; 您仍然必须使用SSL来实现此目的。
上市
如果设置为public
,除了被客户端缓存,它也可以由代理高速缓存; 服务于许多其他用户
Cache-Control: public
无存储
no-store
指定内容不被任何高速缓存高速缓存
Cache-Control: no-store
无缓存
no-cache
表示可以维护缓存,但是缓存的内容将ETag
在被服务之前从服务器被重新验证(例如使用)。也就是说,仍然存在对服务器的请求,但是用于验证并且不下载缓存的内容。
Cache-Control: max-age=3600, no-cache, public
max-age:seconds
max-age
指定内容将被缓存的秒数。例如,如果cache-control
看起来像下面:
Cache-Control: max-age=3600, public
这将意味着内容是公开可缓存的,并且在60秒后将被认为是陈旧的
s-maxage:秒
s-maxage
这里的s-
前缀代表共享。这个指令专门针对共享缓存。像max-age
它也得到的东西被缓存的秒数。如果存在,它将覆盖max-age
和expires
头的共享缓存。
Cache-Control: s-maxage=3600, public
必须重新验证
must-revalidate
有时可能会发生,如果您有网络问题,并且无法从服务器检索内容,浏览器可能无法验证服务陈旧的内容。must-revalidate
避免这种情况。如果存在此伪指令,则意味着在任何情况下都不能提供过时的内容,并且在服务之前必须从服务器重新验证数据。
Cache-Control: max-age=3600, public, must-revalidate
代理重新验证
proxy-revalidate
类似,must-revalidate
但它为共享或代理缓存指定相同。换句话说proxy-revalidate
就是must-revalidate
为s-maxage
是max-age
。但为什么他们不叫它s-revalidate
?我不知道为什么,如果你有任何线索请在下面留下评论。
混合值
但是,您可以结合不同的方式这些指令来实现不同的缓存行为,no-cache/no-store
并且public/private
是互斥的。
如果同时指定no-store
和no-cache
,no-store
将优先于no-cache
。
; If specified both
Cache-Control: no-store, no-cache
; Below will be considered
Cache-Control: no-store
对于private/public
任何未认证的请求,考虑缓存,public
并且对于任何已认证的缓存,考虑缓存private
。
验证器
到目前为止,我们只讨论了内容如何缓存以及缓存内容被视为新鲜的时间,但我们没有讨论客户端如何从服务器进行验证。下面我们讨论用于这个目的的头。
ETag
Etag或“实体标签”在HTTP / 1.1规范中引入。Etag只是服务器附加一些资源的唯一标识符。此ETag稍后被客户端用于进行条件HTTP请求,"give me this resource if ETag is not same as the ETag that I have"
并且仅当etag不匹配时下载内容。
在HTTP文档中未指定生成ETag的方法,并且通常使用一些抗冲突哈希函数来为资源的每个版本分配etag。可能有两种类型的etag,即强和弱
ETag: "j82j8232ha7sdh0q2882" - Strong Etag
ETag: W/"j82j8232ha7sdh0q2882" - Weak Etag (prefixed with `W/`)
强有效的ETag意味着两个资源完全相同,它们之间没有差别。虽然弱ETag意味着两个资源虽然不完全相同但可以被认为是相同的。例如,弱的etag可能对动态内容有用。
现在你知道什么etags是什么,但浏览器如何做这个请求?通过向服务器发出请求,同时在If-None-Match
头中发送可用的Etag 。
考虑这种情况,你打开一个网页,加载了一个标志图像,缓存周期为60秒,ETag为abc123xyz
。大约30分钟后你重新加载页面,浏览器会注意到,新鲜的60秒的标志现在陈旧; 它将触发对服务器的请求,在if-none-match
标题中发送陈旧的标志图像的ETag
If-None-Match: "abc123xyz"
然后服务器将该ETag与当前资源版本的ETag进行比较。如果两个etag匹配,服务器将发送回的响应304 Not Modified
将告诉客户端,它有它的副本仍然是好的,它会被认为新鲜的另一个60秒。如果两个etag不匹配,即徽标可能改变,客户端将被发送新的标志,它将用来替换它所具有的陈旧的标志。
上一次更改
服务器可能包含指示Last-Modified
上次修改某些内容的日期和时间的标头。
Last-Modified: Wed, 15 Mar 2017 12:30:26 GMT
当内容变得陈旧时,客户端将做出一个条件请求,包括在头中调用If-Modified-Since
到服务器以获得更新Last-Modified
日期的最后修改日期; 如果它与客户端具有的日期匹配Last-Modified
,则内容的日期被更新为被认为是新的另一n
秒。如果接收的Last-Modified
日期与客户端具有的日期不匹配,则从服务器重新加载内容并用客户端具有的内容替换。
If-Modified-Since: Wed, 15 Mar 2017 12:30:26 GMT
你现在可能会质疑,如果缓存的内容同时拥有Last-Modified
并ETag
分配给它?那么,在这种情况下,两者都将被使用,即,不会有任何重新下载的资源,如果,只有当ETag
匹配新检索到的,因此Last-Modified
日期。如果ETag
不匹配或Last-Modified
大于来自服务器的内容,则必须再次下载内容。
我从哪说起呢?
现在我们已经涵盖了一切,让我们把一切都放在透视,看看如何使用这些信息。
使用服务器
在我们介绍可能的缓存策略之前,让我补充一点,大多数服务器(包括Apache和Nginx)允许您通过服务器实现缓存策略,这样您就不必与代码中的标头交织。
例如,如果您使用Apache,并且您有静态内容/static
,您可以将以下.htaccess
文件放在目录中,以使其中的所有内容都使用以下方式缓存一年
# Cache everything for an year
Header set Cache-Control "max-age=31536000, public"
您可以进一步使用filesMatch
指令来添加条件,并为不同类型的文件使用不同的缓存策略,例如
# Cache any images for one year
<filesMatch ".(png|jpg|jpeg|gif)$">
Header set Cache-Control "max-age=31536000, public"
</filesMatch>
# Cache any CSS and JS files for a month
<filesMatch ".(css|js)$">
Header set Cache-Control "max-age=2628000, public"
</filesMatch>
或者如果您不想使用该.htaccess
文件,您可以修改Apache的配置文件http.conf
。同样适用于Nginx,您可以在位置或服务器块中添加缓存信息。
缓存建议
没有关于你的缓存策略应该看起来像什么黄金规则或设置标准,每个应用程序是不同的,你必须查找和找到最适合您的应用程序。但是,只是给你一个大概的想法
- 您可以对任何静态内容进行积极缓存(例如缓存一年),并使用指纹文件名(例如
style.ju2i90.css
),以便每当文件更新时缓存都会自动拒绝。还应该注意,你不应该跨越一年的上限,因为它可能不被兑现 - 看看和决定你甚至需要缓存的任何动态内容,如果是多长应该是。例如,在博客的某些RSS馈送的情况下,可以存在几个小时的缓存,但是对于ERP中的库存项目不能有任何缓存。
- 始终在响应中添加验证器(最好是ETag)。
- 在选择缓存内容的可见性(私有或公开)时请注意。请确保您不会在任何公共代理中意外缓存任何特定于用户或敏感内容。当有疑问时,不要使用缓存。
- 将经常更改的内容与不经常更改的内容分开(例如,在javascript包中),以便在更新时不需要使整个缓存内容过时。
- 测试和监控您的网站提供的缓存标头。您可以使用浏览器控制台或
curl -I http://some-url.com
为此目的。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/courses/262861.html