第五章 静态资源 CDN 引入
静态请求 CDN
- 用户将静态资源数据请求到ECS服务器,ECS服务器解析到阿里云的CDN中,CDN可以理解为一个无限大的内容磁盘缓存,本身没有文件存储。当用户访问 getItem 的一个静态资源文件的时候,会根据路由规则查看本地是否有这样的文件,如果有直接返回,没有就回源到源站,回源到下面的OSS中获取静态资源文件。
- CDN一边返回对应的文件,一边将文件按照http指示的生命周期缓存起来,以便下次用户访问时,直接返回。
Cache Control 响应头
Cache Control 状态标志着缓存的策略
-
private
:客户端可以缓存 -
public
:客户端和代理服务器都可以缓存(代理服务器指的是从客户端到后端服务器所经过的中间服务器结点,比如 nginx、CDN、正向代理服务器等) -
max-age=xxx
:缓存的内容将在 xxx 秒后失效 -
no-cache
:强制向服务端再验证一次(客户端缓存在本地,下次使用缓存时要向服务器请求验证是否可以使用缓存) -
no-store
:不缓存请求的任何返回内容
客户端向服务器验证是如何做的呢 ?
有效性判断
-
ETag
:资源唯一标识
- 将请求的内容进行MD5或Hash的加密,生成一串资源唯一标识符,在第一次返回内容的时候,加上ETag返回给客户端浏览器。
- 下一次请求时,发送HTTP请求带上ETag,与服务器本地的ETag做验证,若符合就返回状态码304 (Not Modified) ,表示缓存是有效的,客户端可以直接使用。
-
If-None-Match
:客户端发送的匹配Etag标识符 -
Last-modified
:服务端响应资源的最后修改时间 -
If-Modified-Since
:客户端发送的匹配资源最后修改时间的标识符
整个客户端向浏览器请求流程如下:
首先用户请求资源,
- 先判断URL本地是否有缓存,如果没有就直接向服务器请求,然后返回。
- 如果有,判断缓存是否过期 (
max-age
),若没有过期,则直接使用缓存资源。 - 如果有
max-age
但过期了,则优先判断ETag
:有ETag
的话就向服务器请求If-None-Match
,请求带上ETage
。 - 若没有
ETag
,则判断是否有Last-Modified
,然后向服务器请求If-modified-since
(客户端发送的匹配资源最后修改时间If-None-Match
如果早于服务器响应资源修改时间Last-Modified
,则资源无效已经被修改,如果晚于则资源有效) - 服务器返回的是304表示资源没有修改,则本地缓存可直接使用;如果返回200,表示资源被修改,需要向服务器发起请求
浏览器三种刷新方式
- 回车刷新或a标签连接:看cache-control对应的max-age是否仍然有效,有效就直接使用本地缓存,如果cache-control中为no-cache,则进入缓存协商逻辑(指判断ETage或LastModified这种方式)
- F5刷新或 command+R 刷新:去掉cache-control中的max-age或直接设置max-age为0,然后进入缓存协商逻辑
- 强制刷新 ctrl+F5 或 command+shift+R 刷新:去掉 cache-control 和协商头(带ETage或Last-Modified),强制刷新,从服务器获取资源
缓存协商机制:比较 last-modified 和 ETag 到服务端,若服务端判断没变化则304不返回数据然后客户端直接使用本地缓存,否则200返回数据
CDN 自定义缓存策略
- 可自定义目录过期时间(CDN自身向源站OSS做回源的时间)
- 可自定义后缀名过期时间(针对不同后缀名设置过期时间)
- 可自定义对应权重(设置用自定义后缀名过期时间/自定义目录过期时间二者使用的权重)
- 可通过界面或api强制cdn对应目录刷新(不一定保证成功)
静态资源CDN部署策略
部署策略一
如果静态资源文件(css,js,img)文件名不变,采用max-age缓存时间设置后,如果在缓存有效时间内发生版本更新,比如重大故障或更新,如果全都是让用户来手动刷新浏览器,清缓存,这样体验不好,有以下几种部署策略:
- css,js,img等元素使用带版本号部署,例如a.js?v=1.0不便利,且维护困难(如果单纯改某个文件版本,其他文件是否更新版本号会难以维护)。
- html内嵌css,js,img这些资源,必须设置成
no-cache
,向服务器做缓存协商机制。html一般采用强推的概念,可以设置max-age,但每次请求都会让CDN全部失效,然后回源,这样将 max-age 设置一个短的时间后,用户就有版本更新
- css,js,img等元素使用带摘要部署:例如a.js?v=45edw存在先部署html还是先部署资源的覆盖问题。
- 给资源文件名后加一个部署摘要(一段字符串,如果文件没变化,摘要也不改变),但会存在问题。
- 情况1:先部署资源文件后部署html
- 某个js文件发生变化,更改摘要后如果js先部署,js会覆盖老版本,此时html引用的还是老的js文件,有可能导致不兼容问题;
- 情况2:先部署html后部署资源文件
- 先部署html会引用新的js,而此时服务器还是老的js等,容易出错。
- (推荐)css,js,img 等元素使用摘要做文件名部署,例如45edw.js,新老版本并存,且可回滚,资源文件部署完成后再部署html。
部署策略二
- 对应静态资源保持生命周期内不会变,max-age可设置的很长,无视失效更新周期
- html文件设置no-cache或者较短的max-age,以便于更新
- html文件仍然设置较长的max-age,依靠动态的获取版本号请求发送到后端,异步下载最新的版本号的html后展示渲染在前端
- 动态请求也可以静态化成json资源推送到cdn上
- 依靠异步请求获取后端节点对应资源状态做紧急下架处理
- 可通过跑批仅仅推送cdn内容使其下架等操作
全页面静态化
html,css,js 静态资源cdn化 -> js ajax动态请求cdn化(将请求变成静态文件发送到cdn)–> 全页面静态化
**定义:**在服务端完成html,css,甚至js的load并渲染成纯html文件后直接以静态资源的方式部署到cdn上
phantomjs
首先 phantomjs 是一个无头浏览器,可以借助其模拟 webkit js 的执行
- 修改需要全页面静态化的实现,采用initView和hasInit方式防止多次初始化
- 编写对应轮询生成内容方式
- 将全静态化页面生成后推送到 cdn
总结:经过全页面静态化以后,从以前刷新 ajax 请求填充到 html 这个过程变成了已经执行好的静态html页面