浏览器与CDN缓存浅谈

最近被同事问到CDN的全称是什么?我想了想,反问了一句你知道SOS的全称是什么吗?虽然这场没有硝烟的战争中我们打了一个平手,但我心里依旧不是很开心,天天挂在嘴上说的CDN竟然不知道是啥,感觉深深得丢了前端人的脸。

因此我费了一天的时间研究CDN,终于知道它的全称是Content Delivery Network,即内容分发网络。为啥会用到CDN呢?通常说的CDN缓存又是啥?是人性的险恶还是道德的…?

火车跑偏了…言归正传,文件缓存通常分为两种:本地缓存和服务器缓存。本地缓存就是通常所说的浏览器缓存。

浏览器缓存

1.浏览器:老服(服务器),给我一个58首页;

2.服务器:老浏,你要的index.html,给你;

3.浏览器看到页面中引用的文件(js、css、image等),然后每个文件跟服务器发一份请求。

4.浏览器:老服,给我一个common.css;

5.服务器:给你;

7.服务器:给;

……(此处省略58次请求)

8.浏览器:老服:给我一百块...

9.服务器:过分了啊

10.浏览器拿到所有请求到文件解析并渲染出58首页的页面。

假如用户刷新页面,就会重复上述1—10这几个步骤,当然8、9可以略过,但是像image/css/js这样的静态文件两次请求过程中并没有什么改变,为什么还要再次请求呢?浏览器缓存就产生了。

cache-control

值说明

public

所有内容都将被缓存(客户端和代理服务器都可缓存)

private

内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)

no-cache

必须先与服务器确认返回的响应是否被更改,然后才能使用该响应来满足后续对同一个网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,如果资源未被更改,可以避免下载

no-store

所有内容都不会被缓存到缓存或 Internet 临时文件中

must-revalidation/proxy-revalidation

如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证

max-age=xxx

缓存的内容将在 xxx 秒后失效, 这个选项只在HTTP 1.1可用, 并如果和Last-Modified一起使用时, 优先级较高

例如cache-control:max-age=604800,代表这个文件可以缓存一星期。有了cache-control之后的请求过程如下:

l 服务器:给,这个文件可以缓存在你本地7天,这段时间别跟我要了。

l 浏览器:哦。可是如果这个文件7天内有变更怎么办?别人都玩王者了,我还在打DOTA。

l 服务器:这个文件上次修改时间(Last-Modified)是:2018-05-08 5:58,那你用的时候给我打个电话 ,告诉我一声你缓存文件的这个修改时间(If-Modified-Since),我这边对一下,如果有新的,我会再发你一份,没有你就继续玩DOTA。

l 浏览器:哦。

但仅靠Last-Modified来判断文件是否修改有几个问题:

1. 一些文件也许会周期性的更改,但是他的内容并不改变;

2. If-Modified-Since能检查到的粒度是s级的,某文件如在1秒内修改多次,这种修改无法判断;

3. 某些服务器不能精确的得到文件的最后修改时间;

因此HTTP/1.1引入了Etag字段,来标记文件的版本,浏览器请求对应增加If-None-Match来匹配Etag判断文件是否进行过修改,Etag优先级高于Last-Modified。

Etag的生成跟服务器类型有关系,并没有固定规则,但是必须是资源的唯一标示。

请求过程又变味了:

l 浏览器:老服,给我一个18_forbid.gif;

l 服务器:给,这个文件你可以保存一百年,给你这个文件的暗号(Etag,一般为md5串):balabala小魔仙,如果文件有修改暗号就会变,下次用的时候跟我说一下暗号,我对比一下。

l 浏览器:晓得了。

CDN缓存

浏览器缓存说完了,CDN缓存又是咋回事呢?

对于大型网站(58)而言,用户访问量巨大,如果所有用户都去我们的资源服务器(源站)请求数据,资源服务器会很快崩溃,并且不同网络的用户请求源站速度也不一样。为了提高不同网络用户的访问速度,Internet中提出了新的网络架构,即创建一些最接近用户网络的“边缘”服务器(CDN服务器),CDN缓存就是将文件缓存在这些“边缘”服务器上,如下图:

CDN服务器的内容存取方式也有两种:推送和拉取。第一种就是源站在发布更新文件时,将新文件向所有的CDN服务器都推送一份,这样所有的CDN服务器就都有与源站同样的文件。第二种更像浏览器缓存文件的方式,就是当浏览器请求到就近CDN节点时,该CDN节点没有这个文件时,就去源服务器拉取一份并缓存到当前CDN服务器,过程类似:

l 浏览器:老C(就近CDN服务器),给我一份b.js;

l CDN:目前没有,稍等!老源(源服务器),给我一份b.js;

l 源服务器:给,这个文件可以缓存期限一年;

l CDN:OK,缓存好了。老浏,给你要的b.js,这个文件可以缓存一个月,暗号(Etag):天王盖地虎;

l 浏览器:好的。

n 过了两天……

l 浏览器:老C,b.js暗号——天王盖地虎

l CDN:没错,还是那个 。

看到这你可能会问,那文件变更了怎么办?源服务器上升级到王者了,CDN一年内只能玩DOTA啊!你说的对,我也没办法……

这就是我们的文件变更后为啥要加版本号的原因了,我们的引用文件如果请求链接有任何变化(包括文件名、参数),都不会走原来的缓存文件了,而作为一个新文件去源服务器获取。

用户访问文件的最终顺序就变为了以下方式:

至此,我的牛逼已吃完,欢迎大家批评指正。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20180711G1G4RJ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券