美文网首页
浏览器缓存问题

浏览器缓存问题

作者: 程序媛萌小雪Mxx | 来源:发表于2018-12-18 14:37 被阅读0次

    你有没有注意到,当你第一次访问一个网站的时候,页面要等好久才能呈现出来,如果是第二次访问这个网站的时候,网页呈现速度远远比第一次访问的时候快很多,这是为什么呢?然而这并不是偶然,这是浏览器缓存的缘故。

    浏览器缓存存在的原因

    所有的浏览器都试图将网站的静态资源缓存到本地来减少网页的加载时间,减少网络流量。从远程服务器获取资源消耗的时间要远远超过从本地获取资源的时间。

    浏览器缓存是如何工作的?

    场景一:用户之前没有访问过此网站

    浏览器没有缓存此网站的任何信息,所以首次访问时,所有资源都要从远程服务器拉取。


    image.png

    我们可以看一下浏览器的请求信息

    image.png image.png

    场景二: 用户第二次访问该网站

    浏览器将从 Web 服务器检索 HTML 页面,但是一些静态资源比如 JavaScript、CSS、图片等会直接从本地缓存中获取。


    image.png

    这时我们刷新页面发现,请求时间明显少了很多。


    image.png

    我们可以点击一个静态的 CSS 文件看一下他的请求头,发现他是从本地缓存获取的。


    image.png

    浏览器是如何知道要缓存什么呢?

    浏览器会侦查服务器端 HTTP 返回的头部信息,头部信息中有四个因素决定缓存问题。

    • ETag
    • Cache-Control
    • Expires
    • Last-Modified

    ETag

    ETag(或实体标签)是一个字符串,用作缓存验证。
    服务器可以在其响应中包括ETag,然后浏览器可以在将来的请求(在文件过期之后)中使用ETag来确定缓存是否包含过期的副本。

    如果值是相同的,那么资源没有改变,服务器用304响应代码(未修改)响应,主体是空的。这使浏览器知道使用缓存的副本仍然是安全的。


    image.png

    注意,只有当文件在缓存中过期时,才在请求中使用ETag。

    Cache-Control

    Cache-Control报头有许多我们可以设置的指令来控制缓存,如缓存行为、过期和验证。这些也可以结合在一起。

    Cache Behavior
    Cache-Control: public
    

    public意味着资源可以通过任何缓存(浏览器、CDN等)进行缓存。

    Cache-Control: private
    

    private表示资源只能由浏览器缓存

    Cache-Control: no-store
    

    告诉浏览器总是从服务器获取资源

    Cache-Control: no-store
    

    这个设置可能有点误导,这并不意味着“不要缓存”。他告诉浏览器、缓存服务器,不管本地副本是否过期,使用资源副本前,一定要到源服务器进行副本有效性校验。

    Expiration
    Cache-Control: max-age=60
    

    这指定了应该缓存资源的时间长度,所以max-age=60表示应该缓存1分钟。RFC 2616建议最大值不应超过1年(最大年龄=31536000)。

    Cache-Control: s-max-age=60
    

    这仅供CDN等中间缓存使用。

    Validation
    Cache-Control: must-revalidate
    

    告诉浏览器、缓存服务器,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。

    Expires

    Expires头来自较旧的HTTP 1.0,但是仍然在许多站点上使用。
    这个头部字段提供一个到期日期,在此日期之后,该资源被视为无效。

    Expires: Wed, 25 Jul 2018 21:00:00 GMT
    

    如果Cache-Control中有max-age指令,浏览器将忽略该字段

    Last-Modified

    Last-Modified 也是来自 HTTP1.0

    Last-Modified: Mon, 12 Dec 2016 14:45:00 GMT
    

    此字段包含上次修改资源的日期和时间。

    HTML Meta Tag

    在HTML5之前,使用HTML内部的元标记来指定缓存控制是一种有效的方法

    <meta http-equiv="Cache-control" content="no-cache">
    

    现在不鼓励使用,而且这个特性已经被Web 标准移除,之所以现在在一些浏览器中还有效是因为需要一个适应的过程,如果在项目中用到了要及时更新代码。而且这样做只有浏览器才能够解析此标记并理解它,而中间缓存不会。所以推荐使用HTTP头发送缓存指令来进行缓存设置。

    HTTP Response

    让我们看一个 HTTP 响应的例子

    Accept-Ranges: bytes
    Cache-Control: max-age=3600
    Connection: Keep-Alive
    Content-Length: 4361
    Content-Type: image/png
    Date: Tue, 25 Jul 2017 17:26:16 GMT
    ETag: "1109-554221c5c8540"
    Expires: Tue, 25 Jul 2017 18:26:16 GMT
    Keep-Alive: timeout=5, max=93
    Last-Modified: Wed, 12 Jul 2017 17:26:05 GMT
    Server: Apache
    

    第二行告诉我们缓存时间是1小时
    第五行告诉我们返回的是 png 图片
    第七行告诉我们 ETag 的值,这个值将在一小时以后用来校验资源是否被更改过
    第八行是过期时间,如果设置了第二行的话,这个设置将被视为无效
    第十行告诉我们这个图片最后被编辑的时间

    缓存陷阱

    由上,我们已经确定浏览器缓存是非常棒的,我们应该合理的利用它。

    但是我们希望用户在访问页面时能看到我们网站页面的最新版本。但是我们不能期望他们每次访问我们的站点时都需要进行硬刷新(Ctrl-F5)才行。

    假设我们修复了名为app.min.js的JavaScript文件中的一个bug,并将更新推送到生产站点。

    <script src="assets/js/app.min.js">
    

    但是缓存的过期时间设置的是一周

    Cache-Control: private, max-age=604800
    

    这样有些用户还是会访问原来的app.min.js文件,bug 还是会存在。那我们应该怎么办呢?

    缓存破坏

    缓存破坏是指我们使缓存的文件无效,并强制浏览器从服务器检索文件。

    我们可以通过简单地更改文件名来指示浏览器绕过缓存。对于浏览器来说,这是一个全新的资源,因此它将从服务器获取资源。

    缓存破坏还允许我们为可能频繁变化的资源保留较长的最大年龄值。Google建议将最大年龄设置为1岁(来源)

    Versioning(版本控制)

    我们可以给文件设置一个版本

    assets/js/app-v2.min.js
    

    Fingerprinting(指纹)

    我们可以根据文件内容给文件名添加指纹信息

    assets/js/app-d41d8cd98f00b204e9800998ecf8427e.min.js
    

    添加查询参数

    assets/js/app.min.js?version=2
    

    即使在HTTP响应头中添加了 Cache-control:p public ,很多代理服务器不会缓存带有 “?”的资源,所以不推荐此种方法。

    最好的选择

    推荐:

    • 使用Cache-Control and ETag控制缓存行为来处理静态资源
    • 设置长的最大年龄值,并使用指纹或版本控制来破坏缓存机制

    不推荐:

    • 使用 HTMLmeta 标签来设置缓存行为
    • 使用添加查询参数来破坏缓存机制

    如何设置浏览器不缓存呢?

    Cache-Control: no-cache, no-store, must-revalidate
    

    对学习抱有热情的开发小伙伴欢迎加入 qq群685421881,更欢迎热爱编程的妹子进入,让我们一起学习 并进步吧!

    相关文章

      网友评论

          本文标题:浏览器缓存问题

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