美文网首页让前端飞
静态资源文件的缓存问题

静态资源文件的缓存问题

作者: 江枫 | 来源:发表于2014-10-01 17:24 被阅读1650次

前一阵被人问到一个问题:

开发人员修改一文件,版本下发后期望用户可以访问到修改的最新文件,而不是被浏览器缓存过的历史文件,请问Http有机制可以保证用户访问到最新的文件吗?如果没有,在考虑性能的前提下,如何设计一种可行方案呢?

相信不少人第一直觉会想到和浏览器缓存有关的一些缓存头,例如:

  • 与请求内容新鲜度有关的:expires,cache-control
  1. expires指定了文档的失效时间,但是前提要求客户端和服务器端的时钟是同步的,不然就不准确了
  2. cache-control头比实际想象的要复杂的多,cache-control:no-cache表明不应使用缓存文件,而应该直接从服务器重新获取,cache-control:max-age=3600表明从服务器将文档传来之时起,可以认为此文档处于新鲜状态的秒数。
  • 与条件请求有关的头,If-Modified-Since,If-None-Match,Last-Modified,Etag。
    浏览器认定文档新鲜度过期后,需要重新请求服务器,此时可以附带一些条件参数,例如文档最近一次修改的时间,文档的实体标记etag值,服务器会拿请求报文中的值与服务器中保存的值进行比较,如果两者一致,表明文档还可以继续使用,此时以304(文档未修改)状态码作为回应,否则将新的内容返回客户端。

我们把问题细化一下,修改的文件存在两种情况:

  1. 该文件的内容是需要动态填充的,这时缓存的策略为不缓存,每次请求都去服务器重新验证

  2. 对于静态文件的修改,举几个例子看看:
    下面这个是github页面上公共图标的缓存情况,cache-control配置了一个很大的失效时间,同时结合last-modified头实施缓存策略。


    github页面上公共图标

下面这个是知乎中个人头像的缓存情况,可以看到采用了cache-control和etag控制缓存


知乎个人头像

现在的问题是:上述图标要是发生了改变,用户浏览器如何才能及时得到更新呢?

因为cache-control配置了一个很大的失效时间间隔,在用户本地存在缓存的情况下,浏览器是不会再次发起请求的

  • 对于github的图标还好理解,因为是网站公共的图标,被更改的频率会很小,在这种背景下,可能在下一次用户请求该网站时,用户浏览器已经不存在此网站的缓存了,所以是可以更新到最新状态的。

  • 对于知乎用户头像的缓存策略,初看起来似乎很矛盾,用户更改头像是随时可能会发生的事情,如何在用户头像更改之后网站内容可以及时更新呢?仔细想想,其实我们的担心是多余的,用户上传新的头像后,系统会给新头像分配新名称,这样在用户重新请求主页面时,动态填充的内容已经发生了变化,服务器会返回新的主页面给浏览器,浏览器解析到了新的用户头像连接,由于在浏览器缓存中并没有找到对应的缓存文件,所以浏览器会针对新的用户头像发起Http请求,进而得到最新的用户头像

图片和样式文件的更改一般不会给网站带来灾难性的影响,但如果是js文件被修改但是用户浏览器依旧使用的是过期的缓存文件,这种情况相比较而言对网站的影响就要大得多。

如何避免此类问题呢?结合知乎个人头像的例子,不难想到的一种方案就是对修改的脚本文件添加一个修改的标志,类似下面这个样子

<script src="dir/test.js?modify=true"></script>

如果频繁修改呢,下面这种方式似乎给好一点
<script src="dir/test.js?version=2.0"></script>

上面的方案都是基于script标签的,在模块化大行其道的今天,脚本加载器应该是会考虑诸如此类实际问题的,例如在seajs中有下面的配置功能

seajs.config({ vars: { 'version': '2' } });
define(function(require, exports, module) {
var lang = require('./dir/test.js?version={version}');
});

考虑一下现实吧,假设文件A在系统中很重要,因此存在大量文件引用,如果还采用上述的方案,这无疑是烦人的体力劳动,如何解脱呢?

总体的方案是:

在动态请求的文件中给静态文件动态添加类似于版本号的标志,然后对服务器配置url重写功能(例如apache服务器),在java中可以配置过滤器,对特定的文件进行url重写。

下面给出stackoverflow上一个基于php的实现方案,原文在这里

+ 首先,在apache的配置文件.htaccess中开启重写功能,并且添加规则
RewriteEngine on RewriteRule ^(.*)\.[\d]{10}\.(css|js)$ $1.$2 [L]

  • 给文件追加mtime标志

function auto_version($file){ if(strpos($file, '/') !== 0 || !file_exists($_SERVER['DOCUMENT_ROOT'] . $file)) return $file; $mtime = filemtime($_SERVER['DOCUMENT_ROOT'] . $file); return preg_replace('{\\.([ ^./]+)$}', ".$mtime.\$1", $file); }

  • 实际使用

<script href="<?php echo auto_version('/js/base.js'); ?> />

相关文章

  • “阿里人”分享大型网站架构系列:缓存在分布式系统中的应用

    分布式缓存 CDN,反向代理缓存,主要解决静态文件,或用户请求资源的缓存,数据源一般为静态文件或动态生成的文件(有...

  • 静态资源文件的缓存问题

    前一阵被人问到一个问题: 开发人员修改一文件,版本下发后期望用户可以访问到修改的最新文件,而不是被浏览器缓存过的历...

  • 通过gulp 在原html文件上自动化添加js、css版本号

    所需gulp插件: gulp gulp-rev-dxb为静态文件随机添加一串hash值,解决缓存问题。根据静态资源...

  • Apache配置静态缓存

    老问题,什么是静态缓存?为什么配置静态缓存? 这里的静态文件指的是图片、 js、 css 等文件,用户访问一个站点...

  • 【干货】前端Nginx统一配置

    一、缓存策略 项目入口文件index.html 不缓存,其他静态资源js、css、font、img等走缓存策略,具...

  • 静态文件缓存问题

    问题描述 在日常的项目中,在浏览器加载静态文件,会遇到浏览器缓存的问题。 浏览器会默认使用缓存,当我们修改了静态文...

  • SPA优化

    常见的几种SPA优化方式: 减小入口文件体积(路由懒加载) 静态资源本地缓存(缓存,PWA:Service Wor...

  • html前端进行资源重载及刷新资源

    最近开发webview嵌套开发,遇到资源重载的问题,具体表现在:css缓存强硬,js缓存强硬,无法事实更新静态资源...

  • nginx静态资源缓存服务器

    nginx静态资源缓存服务器 静态资源指的就是网站中固定的文本,图片这些一旦确定就不会变化的文件; 而在反向代理中...

  • 网站慢优化

    静态资源:gzip(压缩静态资源加快响应速度) expires(缓存到客户端,减少http请求)cdn(缓存到客户...

网友评论

    本文标题:静态资源文件的缓存问题

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