静态资源部署问题的一些思考

对访问静态资源的一些思考

  1. 当我还是一个初入门的小前端时,对静态资源的引用方式就是理解为在HTML代码里面,通过一个link或者script标签,写一个相对或者绝对路径,去拿到对应的静态资源。比如下面这样:
<link href="/static/kasol.css" />

没有什么毛病,一切都是那么美好,打开浏览器查看network,发现状态码是200。
但是问题在于,用户在访问页面的时候都要去加载一次这个资源,那其实是不太好的,前端的瓶颈在于带宽,我们需要尽量节约请求数,所以很多时候,我们需要浏览器的缓存机制,可以利用http1.0中的expires或者1.1中的max-age,给响应头写上标记,这样一来,我们下次再来访问这个页面的时候,查看这个请求,状态码应该还是200,但是这次是from cache,我们直接从浏览器的缓存那里拿到了这个静态资源文件。
或者还可以利用not modified 这个标记,这样子当浏览器不确定这个资源是否真的过期时,就可以通过协商缓存机制来询问服务器,假如文件并没有被更新,将会告知浏览器继续使用该资源,响应头状态码变为304。

  1. 当我的资源内容改变时,此时怎么办呢,要怎么让浏览器去获取到最新的文件呢?也许你会说,在url后面加上后缀不就可以了么?
<link href="/static/kasol.css?v=1.0" />

但是这种方式很低效,并且在有多个引用时就变得很繁琐。而且,以这种递增版本号作为后缀的方式不是很科学,为什么?假如这个文件的内容实际上并没有改变,但是你还是改动了这个version,那你又让浏览器重新去发起请求抓取最新文件了,浪费了缓存,所以比较好的方法是,根据文件内容做一个摘要,把这个摘要作为文件的后缀,可能就像下面那样

<link href="/static/kasol.css?v=ask3oe4" />

这样子的话,只有当文件内容确实改变时,我们的浏览器才会发起请求抓取最新的资源。
或者还有人使用的是在获取资源时,在后面加上时间戳,这样确实可以每一次都获取到最新的资源,但是这么一来,就无法利用缓存了。

  1. 现在有点规模的公司,都会把静态资源部署到CDN上,而不是直接丢到提供服务的机器上,CDN的好处不言而喻,但是当这些资源抽离出来被放到了CDN上后,又有一个新的问题了,就以上面的场景来说:举个例子,比如某个时刻,后端的页面结构发生了改变,同时,对应的css文件和js文件也发生了改变,这时候需要发布上线了,那么我们是先发前端应用还是先发后端应用呢?
  • 假如先发后端,那么在后端部署完成,而前端没有部署完的情况下,此时有用户来访问页面,虽然请求想获取的是最新的资源,但是此时前端的资源还是旧的,这时肯定就不对了,更糟糕的是,浏览器还把这个旧的资源缓存了,所以除非用户主动强制刷新,或者有缓存更新机制,不然拿到的就是旧的资源了
  • 假如先发前端,再发后端,那么同样的,在部署的时间间隔内,用户会拿到旧的页面,配上新的静态资源,这样也是不对的。不过当后端部署完成后,拿到了新的页面,此时就正常了。

其实以上说的可以看出,俩种方式都是有点问题的。

  1. 再说上述问题的答案之前,先提一个关键点,就是我们发布前端资源的姿势。大致可以分为增量部署和覆盖式部署。前者可以看成是在机器上多了一个版本的文件,而后者则是覆盖掉原来的文件。我们可以根据前端应用的某个标志。比如package.json的version来控制是否是增量发布,比如你改动了kasol.css,但是不改version,他原先的版本号是1.0.0,那么发布的时候,那么他就会在1.0.0这个文件夹下把原先的资源给覆盖了,同理,假如改动了kasol.css,并且版本号升级为了1.0.1,那么发布的时候,会在1.0.1这个文件夹下生成资源,不会去覆盖1.0.0这个文件夹。

  2. 那么比较好的做法是怎么样的呢?
    首先我们利用构建工具生产出来的静态资源文件应该是这样的姿势

kasol.ae2sk2o.css

然后在页面上,自然是去这样引用

<link href="/static/kasol.ae2sk2o.css" />

区别在哪呢,可以看到,那个摘要的值从后缀移动到了文件的扩展名中。这样当后端的页面去获取资源的时候,只要这个摘要不同,抓取的资源就是不一样的。

  1. 但是第三点中提到的,不管先部署哪一种应用貌似都会有问题,不过现在看来。我们可以先部署前端静态资源,再部署后端应用。为什么这么说呢?举个覆盖式部署的例子:
    原先旧版本的页面结构是这样
<link href="http://xxx.cdn.com/path/kasol.ae2sk2o.css" />

CDN上的静态资源是这样

http://xxx.cdn.com/path/kasol.ae2sk2o.css

现在静态资源改变了,变成了下面这样

http://xxx.cdn.com/path/kasol.ksoplw.css

虽然后端没有什么逻辑更改,但是我们需要改变后端的引用:

<link href="http://xxx.cdn.com/path/kasol.ksoplw.css" />

可能有人会说,按照上述的逻辑,用户在时间间隔内假如去访问旧的页面,由于后端的引用没有更新,那么抓取的还是http://xxx.cdn.com/path/kasol.ae2sk2o.css ,由于是覆盖式部署,此时已经被新的覆盖掉了,是不是应该404了?
其实仔细观察上述静态资源就会发现,除了文件扩展名中的部分hash值不同,其他都是一样的。所以要是后端应用可以自动感知到新的hash并应用,那就好了。
所以我们可以这样来处理,前端构建完静态资源后,生成一个Map,也丢到CDN上去,本质上就是类似一个JSON对象,比如名字叫1.0.0.map,他大概长这样。

{
   key:'kasol.css',value:'kasol.ae2sk2o.css'
}

当更新完静态资源,map也会变化,比如这样

{
   key:'kasol.css',value:'kasol.ksoplw.css'
}

这个map也是跟着版本号走的,对于不同的版本号,都有各自的map。
然后我们在后端应用部署一个SDK,他的作用就是轮询去获取对应版本前端资源的map对象,然后在模板中把静态资源的hash值丢进去,这样一来,实际上假如后端应用本身没有逻辑更改,就不需要去发布后端应用,只要发布前端应用即可。等发布完成之后,后端模板会自动去获取最近的资源。
再来说说增量式发布,这种情况大多是后端也改了一些DOM结构,所以此时后端应用也是需要发布的。还是以先部署前端应用来说:首先kasol.ksoplw.cssb并不会把之前kasol.ae2sk2o.css给覆盖掉,而是多了这一个带hash物理文件。
接着在后端未部署完成的时间间隔内,用户访问旧的页面,此时后端的SDK通过轮询拿的还是旧版本的map,所以还是抓取旧版本的资源,即http://xxx.cdn.com/path/kasol.ae2sk2o.css,旧的页面配上旧的静态资源,没什么问题。然后当后端也部署完成后,后端SDK拿到新的map,将新的hash值放到页面里去,新的页面结构会去抓取http://xxx.cdn.com/path/kasol.ksoplw.css,此时就可以击穿缓存,去CDN上拿到新的静态资源。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值