zoukankan      html  css  js  c++  java
  • 浏览器缓存机制

    本文整理在,我的github上。欢迎Star。

    关于3xx系列的状态码

    • 300 多资源选择
    • 301 永久重定向
    • 302 临时重定向
    • 303 告诉用户,使用另一个url获取资源

    主要目的是允许POST请求的响应将客户端定位到某个资源上。比如说,在文件上传完成后让客户端自动重定向到一个上传成功的结果页面。

    • 307 通知用户临时从其他URL响应,重定向的页面展示给用户,让用户去点重定向URL链接。
    • 304 服务端没有变更

    通知浏览器,可以使用缓存。这篇博文要描述的重点

    浏览器(http)缓存机制

    类型

    说到浏览器缓存,通常会遇到一下两种。

    • 200(from cache)
    • 304

    那么,这两种http状态,对应什么样的机制,流程呢?

    缓存机制

    综合以上描述,浏览器在请求一个资源时,使用缓存的流程大概如下。

    1. 首先浏览器会判断,这个资源是否有缓存。没有的话,正常请求。
    2. 如果有缓存的话,浏览会判断缓存是否过期。如果缓存没有过期,则直接使用。此时就是 200(from cache)

    通过上次缓存留下的:cache-control max-age 和 Expires。
    注意:cache-control的优先级高于Expires。

    1. 如果浏览器的缓存过期了,它会请求服务器。服务器会校验缓存的数据是否真的发生了更改。如果服务器端发现数据没有变。就会返回一个304告诉浏览器,你请求的数据 “Not Modified”,可以继续用缓存。同时,浏览器会更新缓存首部的过期时间等信息。

    这里浏览器发起请求时,会用到上次缓存首部的Last-Modified/E-tag。
    具体做法是:
    取出上次缓存的Last-Modified的值,放在本次请求header的 If-Modified-Since 中。
    取出上次缓存的E-tag的值,放在本次请求header中的 If-None-Match 中。
    服务器会据此判断资源是否发生过修改,浏览器中的缓存是否依然可用。

    1. 如果服务器端修改了上次缓存的内容,则直接返回200,并携带新的内容。
    ![浏览器缓存流程图](https://img2018.cnblogs.com/blog/395192/201904/395192-20190411010046819-1241623313.png)

    相关http头

    上文中提到了几个http头,这里做一下详细的解释。

    Cache-Control

    • public: 所有内容都将被缓存
    • private: 内容只缓存到似有缓存中
    • no-cache: 所有内容都不会被缓存
    • no-store: 所有内容都不会被缓存到缓存或者internet临时文件中
    • must-revalidation/proxy-revalidation: 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证(主要用于控制浏览器的前进、后退)
    • max-age=xxx( xxx is numeric ): 缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

    Expires

    头部字段提供一个日期和时间。
    (cache-control max-age 和 s-maxage 将覆盖 Expires 头部。)

    Last-Modified/E-tag

    • 若服务器在响应一个资源时添加了Last-Modified字段,那么当下一次浏览器再一次向服务器请求该资源时(前提是浏览器中上一次的资源被缓存过了),会在请求header中包含If-Modified-Since字段,且值与服务器第一次响应给浏览器的Last-Modified字段一致。

    • 若服务器在响应一个资源时添加了ETag字段,那么当下一次浏览器再一次向服务器请求该资源时(前提是浏览器中上一次的资源被缓存过了),会在请求header中包含If-None-Match字段,且值与服务器第一次响应给浏览器的ETag字段一致
      那么上述是遵循了Http协议的浏览器会自动实现的,而要实现304的功能,就需要服务器(比如Apache对于静态资源会自动实现这两个字段的响应)或者我们手动在服务器端编写响应的逻辑来实现。

    写到这,整个浏览器及http缓存机制应该彻底介绍清楚了。
    那么,就只剩下如何应用了。

    原理与应用

    静态资源

    所谓静态资源,就是很少会修改的内容,包括前端常年打交道的css、js及图片文件等等。
    通常情况下,静态资源的http头是这样配置的。

    Cache-Control: public, max-age=31536000
    Expires: (一年后的今天)
    ETag: (基于内容生成)
    Last-Modified: (过去某个时间)
    Vary: Accept-Encoding
    

    到这里,可以据此给站点中全部的静态资源配置缓存头。这里我有两个建议。

    • 建议给每个静态资源路径添加指纹信息。可以使用gulp或者webpack等构建工具。通过不同版本的指纹信息控制更新缓存。
    • 项目中引用的依赖,建议使用CDN资源。依据缓存原理,浏览器只要访问过相同CDN的资源,就会留下缓存,哪怕其他站点。

    动态资源

    基础配置

    对于非私密性和经常性变动的资源,我们可以这样做。

    Cache-Control: public, max-age=0
    Expires: (当前时间)
    ETag: (基于内容生成)
    Last-Modified: (过去某个时间)
    Vary: Accept-Encoding
    

    这样配置的意义在于,内容可以被浏览器缓存起来。但是因为过期时间的问题,每次都会到服务端判断是否过期。未过期的话,就会收到304,进而继续使用缓存。

    控制返回、前进

    你如果需要更严格的控制,需要告知浏览器即使当用户点击了「返回/前进」按钮,也需要重新检查这些资源文件,那么可以使用:

    Cache-Control: public, no-cache, no-store
    

    私密性缓存

    对于私密或者针对用户的内容,需要把 public 替换为 private 以避免内容被代理缓存。

    Cache-Control: private, …
    

    关于ETag

    建议避免使用 ETag。尤其是使用Apache,又配置了负载均衡的情况下。

    针对生成的 ETag,默认的Apache方法需要把文件的索引节(inode),大小(size)和最后修改时间作为输入求值得到。这会导致在负载均衡的环境中,生成的 ETag 值变得毫无用处,因为每个服务器都会针对相同的文件生成一个不同的 Etag 值。这个可能就是唯一的问题导致很多人完全禁用 ETag,其实只要精确地针对一个匹配的文件生成一个独一无二的 ETag 值,就没有必要禁用 ETag 了。

    Vary: Accept-Encoding

    指定“Vary: Accept-Encoding”标头,用一句话来说明它的意义,就是“告诉代理服务器缓存两种版本的资源:压缩和非压缩,这有助于避免一些公共代理不能正确地检测Content-Encoding标头的问题。
    还有一个现实的原因:IE 浏览器不缓存任何带有 Vary 头但值不为 Accept-Encoding 和 User-Agent 的资源。所以通过这种方式添加这个头,才能确保这些资源在 IE 下被缓存。
    总的来说,加这么一句肯定没错,相当于“多喝热水”。

    参考文献

  • 相关阅读:
    javascript语句——表达式语句、块语句、空语句和声明语句
    javascript运算符——条件、逗号、赋值、()和void运算符
    javascript运算符——位运算符
    javascript运算符语法概述
    javascript类型系统——undefined和null
    javascript类型系统——日期Date对象
    javascript中关于日期和时间的基础知识
    javascript中Date对象的应用——简易日历的实现
    javascript类型系统——Math对象
    photoshop学习目录
  • 原文地址:https://www.cnblogs.com/mcad/p/10687237.html
Copyright © 2011-2022 走看看