在前面的一篇文章中,我讨论了HTTP和它在这一点上的立场。这是一个将专门关于缓存。作为用户,我们很容易因为缓冲视频,加载几秒钟的图片,由于内容正在加载而卡住的网页而感到沮丧。从一些缓存加载资源比从源服务器获取资源要快得多。它减少延迟,加速资源加载,减少服务器上…
在前面的一篇文章中,我讨论了HTTP和它在这一点上的立场。这是一个将专门关于缓存。
作为用户,我们很容易因为缓冲视频,加载几秒钟的图片,由于内容正在加载而卡住的网页而感到沮丧。从一些缓存加载资源比从源服务器获取资源要快得多。它减少延迟,加速资源加载,减少服务器上的负载,降低带宽成本等。
什么是Web缓存?它是位于客户端和服务器之间的某处,持续查看请求及其响应,查找可以缓存的任何响应。以便在再次进行相同请求时消耗更少的时间。
注意,这个图像只是给你一个想法。根据缓存的类型,实现缓存的位置可能会有所不同。更多这一点。
在我们进一步详细介绍之前,让我在文章中进一步介绍将要使用的术语
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。
另一个从老,前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指定内容将被缓存的秒数。例如,如果cache-control看起来像下面:
Cache-Control: max-age=3600, public
这将意味着内容是公开可缓存的,并且在60秒后将被认为是陈旧的
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或“实体标签”在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,您可以在位置或服务器块中添加缓存信息。
没有关于你的缓存策略应该看起来像什么黄金规则或设置标准,每个应用程序是不同的,你必须查找和找到最适合您的应用程序。但是,只是给你一个大概的想法