HTTP缓存

作者: xzz4632 | 来源:发表于2019-07-12 10:49 被阅读0次

    1. 与HTTP缓存有关的header字段

    1.1 Cache-Control

    缓存控制
    注:Cache-Control属于HTTP 1.1规范, 因此只对实现了HTTP 1.1规范的浏览器有效.

    1.2 Expires

    过期时间, 即指定具体的过期时间点, 这要求浏览器与服务器时间同步.
    注:Expires属于HTTP 1.0规范, 如果同时存在Cache-Control, Cache-Control有较高的优先级.

    1.3 Last-Modified

    最后修改时间

    1.4 Etag

    服务器生成的验证标签.

    2. Spring HTTP缓存配置

    2.1 CacheControl

    支持与Cache-Control有关的设置. 可以在以下对象的参数:

    • controllers:
    ResponseEntity.ok().cacheControl(cacheControl).body("");
    

    注:ResponseEntity.ok()生成的BodyBuilder对象还可以添加其他header信息.

    • WebContentInterceptor
      可以用作WebContentInterceptor对象参数. 这个类继承了WebContentGenerator且实现了HandlerInterceptor接口.

    • 静态资源

    // Java配置
    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/resources/**")
                    .addResourceLocations("/public-resources/")
                    .setCacheControl(CacheControl.maxAge(1, TimeUnit.HOURS).cachePublic());
        }
    }
    
    // Xml配置
    <mvc:resources mapping="/resources/**" location="/public-resources/">
        <mvc:cache-control max-age="3600" cache-public="true"/>
    </mvc:resources>
    

    注意:如果在响应头中只设置了Cache-Control, 而没有设置其他有关项, 测试时先请求一次, 然后打开一个新的窗口输入相同的URL, 此时其Status Code显示为`200 (from disk cache).

    2.2 Expires

    获取时间

    ZonedDateTime expiresDate = ZonedDateTime.now().with(LocalTime.MAX);
    String expires = expiresDate.format(DateTimeFormatter.RFC_1123_DATE_TIME);
    
    2.3 Last-Modified

    这是一个验证器, 当在响应头中添加了Last-Modified, 在下次请求这个URL时其请求头就会有If-Modified-Since字段, 在后台可用WebRequest对象对其进行验证.

    // 注WebRequest可以直接注入到@RequestMapping方法中
    if (webRequest.checkNotModified(expiresDate.toEpochSecond()*1000)) {
        return null;
    }
    

    这个有一定的限制, 它只能跟踪文档的修改时间, 不能对内容进行跟踪.

    2.4 Etag

    HTTP1.1 新增规范, 这也是一个验证器, 当响应返回Etag后, 再次请求时会携带If-None-Match字段, 其值为上次响应所返回的Etag字段值. 可以在服务器端通过WebRequest对象的checkNotModified(String etag)进行验证.

    注:WebRequest的checkNotModified有三个重载方法:

    // 验证last-modified
    boolean checkNotModified(long lastModifiedTimestamp)
    // 验证etag
    boolean checkNotModified(String etag)
    // 二者同时验证
    boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp);
    

    3. Etag过滤器

    spring提供了一个Etag过滤器ShallowEtagHeaderFilter, 可以根据响应内容生成Etag值并添加到响应中. 从而节省带宽,但这并不节省CPU时间。




    1. 什么是HTTP缓存, 为什么要使用它?
      http缓存位于服务器与浏览器之间, 用来监视请求, 并保存这个请求的响应副本(如html页面, 图片, 文件等), 然后当有一个与之完全相同的请求时, 这个请求可以使用之前保存的响应副本而不用从服务器下载相同的响应内容.
      使用它的目的有两个: 一个是减少延迟, 另一个是减少网络流量.

    2. web缓存的种类?
      2.1 浏览器缓存
      缓存存储在电脑的硬盘上, 这对于点击后退按钮或查看已查看过的网页非常有用, 这会直接从缓存中获取. 另外, 如果在网站中用了同样的导航图片, 这些图片都将会从缓存中提供.
      2.2 代理缓存
      代理缓存的工作原理与浏览器缓存大致相同,但规模要大得多。由于代理缓存不是浏览器或服务器的一部分,而是在网络上,所以请求必须以某种方式路由到它们。一种方法是使用浏览器的代理设置手动告诉它使用什么代理; 另一个是使用拦截, 由底层网络将web请求重定向到代理,因此不需要为它们配置客户机。
      代理缓存是一种共享缓存;它们通常拥有大量用户,而不是只有一个人在使用它们。

    3. WEB缓存是怎样工作的?
      3.1 缓存规则

      • 如果响应的头信息表示不要缓存响应内容,缓存就不会保存它。
      • 如果请求是经过身份验证或是安全的(如HTTPS),它的响应内容将不会被共享缓存保存。
      • 缓存内容在如下条件下会被认为是有效的: 一是如果在响应头信息中设置了过期时间或有效期, 在有效期内它是有效的. 二是如果发起了请求, 但是这个请求的内容并没有被更改, 此时缓存内容也是有效的.
      • 如果缓存过期,则会要求服务器验证它,并告诉缓存它所缓存的内容是否仍然有效。
      • 在某些情况下(例如,当它与网络断开连接时),缓存也可以提供过期的缓存内容。

    如果响应中既没有验证器(ETag或Last-Modified头),也没有有效期信息,那么响应将不会被缓存.
    总之,有效期和验证是缓存处理内容的最重要方式。

    1. 怎样控制缓存?
      通过HTTP headers

    4.1 Pragma: no-cache
    该设置只对少部分有效.

    4.2 Expries
    都支持. 它指定了缓存的过期时间点. 超过了这个时间点, 会请求服务器并确认先前的缓存内容是否被更改.
    这个过期时间通常被设置为一个基于客户端最后一次访问时间的时间,或者是服务器上文档的最后更改时间。

    Expires头特别适合缓存静态资源(如导航栏和按钮, 图片等)。因为它们变化不大,所以你可以对它们设置非常长的过期时间。这对定期更改的页面也很有用。例如,如果你每天早上6点更新一个新闻页面,你可以将页面设置为此时过期,这样缓存就知道什么时候可以获得一个新的副本,而无需用户点击“reload”。
    Expires头中的值是一个HTTP日期;请记住这个HTTP日期是格林尼治标准时间(GMT),而不是本地时间。
    Expires: Fri, 30 Oct 1998 14:19:41 GMT

    尽管Expires头很有用,但它有一些限制。首先,Web服务器上的时钟和客户端缓存必须同步;如果他们的时间不同,缓存可能错误地认为旧的内容是新的。Expires的另一个问题是,很容易忘记设置了一些内容在特定时间过期, 如果在过期之前不更新过期时间,那么过期后每个请求都会请求Web服务器,从而增加负载和延迟。

    如果使用Expires头,确保Web服务器的时钟是准确的非常重要。一种方法是使用网络时间(NTP);

    4.3 Cache-Control
    HTTP 1.1引入了一个新的报头,Cache-Control,以使Web发布者对其内容有更多的控制,并解决Expires的限制。
    用法如下:

    • max-age=[seconds]
      指定缓存有效期.

    • s-maxage=[seconds]
      与max-age类似,只是它只适用于共享(例如,代理)缓存。

    • public
      在任何场景下都可被缓存;通常,如果需要HTTP身份验证,响应将自动成为private

    • private
      允许特定于一个用户的缓存(例如,在浏览器中)存储响应; 但不能用于共享缓存.

    • no-cache
      强制缓存每次在使用缓存副本之前将请求提交给服务器进行验证。这有助于确保身份验证(与public结合),或者在不牺牲缓存的所有好处的情况下保证获取到的内容是最新的。

    • no-store
      禁用缓存

    • must-revalidate
      严格遵守你所定义的缓存规则。在某些特殊情况下, HTTP缓存允许使用过期的缓存内容;通过指定这个头,将会严格遵循你所定义的规则。

    • proxy-revalidate
      must-revalidate类似,只是它只适用于代理缓存。

    示例:
    Cache-Control: max-age=3600, must-revalidate

    当同时存在Cache-Control和Expires时,Cache-Control优先.

    4.4 验证
    当缓存内容发生更改时,服务器和缓存使用验证进行通信。通过验证,缓存器可以避免在本地已经有一个相同的副本时下载整个与之相同的内容.

    验证器非常重要;如果不存在,并且没有任何可用的有效期信息(Expires或Cache-Control),将不会缓存任何内容。

    最常见的验证器是文档最后更改的时间,即last - modified。当缓存存储了包含last - modified头部的响应时,它可以使用if - modified - since请求来询问服务器该内容自上次被获取以来是否发生了更改。

    HTTP 1.1引入了名为ETag的新验证器。ETags是由服务器生成的唯一标识符,每次更新内容时都会更改。因为服务器控制如何生成ETag,所以缓存可以确保当ETag发出if - none - match请求时,如果匹配,那么缓存内容与实际内容是相同的。

    几乎所有缓存都使用Last-Modified时间作为验证器;ETag验证也变得越来越普遍。

    大多数现代Web服务器都将生成ETag和Last-Modified头,以自动用作静态内容(文件)的验证器;而你什么都不用做。但是,他们对动态内容(如CGI、ASP或数据库站点)了解得不够,无法生成动态内容.

    关于web缓存的用法:

    • 使用一致的URL:
      这是缓存的黄金法则。如果在不同的页面、不同的用户或不同的站点上提供相同的内容,则应该使用相同的URL。
    • 如果资源(特别是可下载的文件)发生更改,请更改其名称。这样你就可以使它在未来很长时间内有效,同时仍然保证提供了正确的版本; 但是链接到它的页面需要保持较短的过期时间。
    • 只在必要时使用cookie. cookie很难缓存,而且在大多数情况下并不需要。如果必须使用cookie,则将其使用限制为动态页面。
    • 使用REDbot检查你的页面

    常见问答:

    • 我知道缓存很好,但是我需要统计访问我的页面的人数!
      如果您必须知道每次访问一个页面时,请选择页面上的一个小项目(或页面本身),并通过给它一些合适的headers且使其不被缓存。例如,您可以从每个页面引用一个1x1透明的不可缓存的图像。Referer头将包含关于页面访问的信息。请注意,即使这样也不能提供关于用户的真正准确的统计数据,对互联网和你的用户不友好;它产生了不必要的流量,并迫使人们等待那个没有被下载的项目。

    • 我的页面有密码保护;代理缓存如何处理它们?
      默认情况下,使用HTTP身份验证保护的页面被认为是私有的;它们不会被共享缓存保存。但是,您可以使用Cache-Control: public header将经过身份验证的页面公开;然后,符合HTTP 1.1的缓存将允许缓存它们。
      如果希望这样的页面可以缓存,但仍然对每个用户进行身份验证,请组合Cache-Control: public和no-cache头文件。这告诉缓存,在从缓存释放表示之前,必须将新客户机的身份验证信息提交给源服务器。
      最好尽量减少身份验证的使用, 对于某些不需要进行身份验证的内容就不要进行身份验证了.

    • 如果人们通过缓存访问我的站点,我应该担心安全性吗?
      https://页面不会被代理缓存缓存(或解密),所以您不必担心这个问题。但是,由于缓存http://响应和通过它们获取的url,您应该注意不安全的站点; 毫无顾忌的管理员可以收集用户的信息,特别是在URL中。
      事实上,您的服务器和客户机之间的网络上的任何管理员都可以收集这类信息。一个特殊的问题是CGI脚本将用户名和密码放入URL本身;这使得其他人查找和使用他们的登录变得非常简单。

    • 我的映像将在一个月后过期,但是我现在需要在缓存中更改它们!
      这个Expires报头不能被绕过;除非缓存(浏览器或代理)耗尽空间并必须删除表示,否则在此之前将使用缓存副本。
      最有效的解决办法是改变它们的链接;这样,全新的响应将从服务器加载。另外也可以在客户端删除缓存.

    • 我已经将我的页面标记为可缓存的,但是我的浏览器在每次请求时都不断地请求它们。如何强制缓存保留它们的表示?
      缓存不需要保存一个表示并重用它;他们只是被要求在某些条件下不保存或不使用它们。所有缓存都根据它们的大小、类型(例如,图像vs. html)或它们保留本地副本的空间大小来决定保留哪些表示。与更受欢迎或更大的版本相比,您的版本可能不值得保留。

    https://www.mnot.net/cache_docs/#REF

    相关文章

      网友评论

        本文标题:HTTP缓存

        本文链接:https://www.haomeiwen.com/subject/fsrkkctx.html