dns服务器将静态资源的请求路由到对应的cdn(内容分发网络 即无限大的内容磁盘缓存) 当用户要访问静态资源文件时 cdn只需要根据路由规则查看本地是否有此文件 有则直接返回 没有则回源到源站 取得静态资源文件后 一边将其返回 一边按照http指定的生命周期缓存起来
1.注册域名
2.根据域名和服务器ip新建cdn
3.将得到的cname配置到域名的解析规则
private:客户端可以缓存
public:客户端和代理服务器都可以缓存
max-age=xxX∶缓存的内容将在xxx秒后失效
no-cache:强制向服务端再验证一次(会将数据缓存在客户端 但在下次使用时会像服务端验证此缓存是否能使用)
no-store :不缓存请求的任何返回内容
有效性判断
ETag :资源唯─标识
If-None-Match :客户端发送的匹配Etag标识符
Last-modified :资源最后被修改的时间多多改日
If-Modified-Since:客户端发送的匹配资源最的标识符
回车刷新或a链接:看cache-control对应的max-age是否仍然有效,有效则直接from cache,若cache-control中为no-cache,则进入缓存协商逻辑
F5刷新或command+R刷新:去掉cache-control中的max-age或直接设置max-age为0,然后进入缓存协商逻辑
ctrl+F5或commond+shift+R刷新:去掉cache-control和协商头,强制刷新
可自定义目录过期时间
可自定义后缀名过期时间
可自定义对应权重
可通过界面或api强制cdn对应目录刷新(非保成功)
1.1css,js,img等元素使用带版本号部署,例如a.js?v=1.0
缺点:基于文件级别的更新不便利 且维护困难 若只更新了一部分文件 那没有变动的文件的版本号是否需要也改变?
浏览器如果不强制清除缓存 则缓存时长以max-age为准 由于css js img都内嵌在html中
第一种方式:html文件必须设置为no-cache 即每次访问必须向服务器验证 所以处于性能考虑 html中的内容不能有太多
第二种方式:html会采取强推策略 html可以设置max-age为较短时间 并在更新时强制让所有cdn失效
第三种方式:让html文件尽可能小 减少发生变化的次数
1.2css,js,img等元素使用带摘要部署,例如a.js?v=45edw
缺点:存在先部署html还是先部署资源的覆盖问题
js会覆盖 html也会覆盖 性能html不能访问原js 原html也不一定能访问新js
1.3css,js,img等元素使用摘要做文件名部署,例如45edw.js
优点(采用此策略):新老版本并存且可回滚,资源部署完后再部署html
2.1对应静态资源保持生命周期内不会变,max-age可设置的很长,无视失效更新周期
2.2html文件设置no-cache或较短max age,以便于更新
2.3html文件仍然设置较长的max age,依靠动态的获取版本号请求发送到后端,异步下载最新的版本号的html后展示渲染在前端:html启动的时候都有一个ajax请求头带着版本号请求服务端调用动态接口 从而得知是否为最新版 若不是则重新渲染一遍 完成之后再推到前端 即异步更新策略(采用此策略)
3.1动态请求也可以静态化成json资源推送到cdn上
3.2依靠异步请求获取后端节点对应资源状态做紧急下架处理
3.3可通过跑批紧急推送cdn内容以使其下架等操作
定义︰在服务端完成html , css,甚至js的load渲染成纯html文件后直接以静态资源的方式部署到cdn上
phantomjs的应用:
修改需要全页面静态化的实现,采用initView和hasInit方式防止多次初始化
编写对应轮讯生成内容方式
将全静态化页面生成后推送到cdn
修改getitem.html
<html>
<head>
<meta charset="UTF-8">
<link href="static/assets/global/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
<link href="static/assets/global/css/components.css" rel="stylesheet" type="text/css"/>
<link href="static/assets/admin/pages/css/login.css" rel="stylesheet" type="text/css"/>
<script src="static/assets/global/plugins/jquery-1.11.0.min.js" type="text/javascript">script>
<script src="./gethost.js" type="text/javascript">script>
<title>Titletitle>
head>
<body class="login">
<div class="content">
<h3 class="form-title">product detailsh3>
<div id="promoStartDateContainer" class="form-group">
<label style="color:blue" id="promoStatus" class="control-label">label>
<div>
<label style="color:red" class="control-label" id="promoStartDate" />
div>
div>
<div class="form-group">
<div>
<label class="control-label" id="title" />
div>
div>
<div class="form-group">
<div>
<img style="width:200px;height:auto;" id="imgUrl">
div>
div>
<div class="form-group">
<label class="control-label">descriptionlabel>
<div>
<label class="control-label" id="description" />
div>
div>
<div id="normalPriceContainer" class="form-group">
<label class="control-label">pricelabel>
<div>
<label class="control-label" id="price" />
div>
div>
<div id="promoPriceContainer" class="form-group">
<label style="color:red" class="control-label">Promotional pricelabel>
<div>
<label style="color:red" class="control-label" id="promoPrice" />
div>
div>
<div class="form-group">
<label class="control-label">stocklabel>
<div>
<label class="control-label" id="stock" />
div>
div>
<div class="form-group">
<label class="control-label">saleslabel>
<div>
<label class="control-label" id="sales" />
div>
div>
<div class="form-actions">
<button class="btn blue" id="createOrder" type="submit">
Buy now
button>
div>
<input type="hidden" id="isInit" value="0">
div>
body>
<script>
var g_itemVO = {};
function hasInit() {
var isInit = $("#isInit").val();
return isInit;
}
function setHasInit() {
$("#isInit").val("1");
}
function initView() {
var isInit = hasInit();
if (isInit == "1") {
return;
}
// 获取商品详情
$.ajax({
type: "GET",
url: "http://"+g_host+"/item/get",
data: {
"id": getParam("id"),
},
xhrFields:{
withCredentials:true
},
success: function(data) {
if (data.status == "success") {
g_itemVO = data.data;
reloadDom();
setInterval(reloadDom, 1000);
setHasInit();
} else {
alert("Failed to get information due to " + data.data.errMsg);
}
},
error: function(data) {
alert("Failed to get information due to " + data.responseText);
}
});
}
$(document).ready(function() {
// 获取商品详情
initView();
$("#createOrder").on("click", function() {
var token = window.localStorage["token"];
if (token == null) {
alert("Not logged in, can't place an order.");
window.location,href="login.html";
return false;
}
$.ajax({
type: "POST",
url: "http://"+g_host+"/order/createorder?token="+token,
contentType: "application/x-www-form-urlencoded",
data: {
"itemId": g_itemVO.id,
"promoId": g_itemVO.promoId,
"amount": 1,//暂时写死为一件
},
xhrFields:{
withCredentials:true
},
success: function(data) {
if (data.status == "success") {
alert("successfully ordered");
window.location.reload();
} else {
alert("The order failed, the reason is " + data.data.errMsg);
if (data.data.errCode == 20003) {
window.location.href="login.html";
}
}
},
error: function(data) {
alert("The order failed, the reason is " + data.responseText);
}
});
});
});
function reloadDom() {
$("#title").text(g_itemVO.title);
$("#imgUrl").attr("src", g_itemVO.imgUrl);
$("#description").text(g_itemVO.description);
$("#price").text(g_itemVO.price);
$("#stock").text(g_itemVO.stock);
$("#sales").text(g_itemVO.sales);
if (g_itemVO.promoStatus == 1) {
// 秒杀活动还未开始
console.log(g_itemVO.startDate);
var startTime = g_itemVO.startDate.replace(new RegExp("-", "gm"), "/");
startTime = (new Date(startTime)).getTime();
var nowTime = Date.parse(new Date());
var delta = (startTime - nowTime) / 1000;
if (delta <= 0) {
// 活动开始了
g_itemVO.promoStatus = 2;
reloadDom();
}
$("#promoStartDate").text("The seckill event will be sold on the "+g_itemVO.startDate+"with a "+delta+"-second countdown");
$("#promoPrice").text(g_itemVO.promoPrice);
$("#createOrder").attr("disabled", true);
} else if (g_itemVO.promoStatus == 2) {
// 秒杀活动进行中
$("#promoStartDate").text("The promotion is in progress");
$("#promoPrice").text(g_itemVO.promoPrice);
$("#createOrder").attr("disabled", false);
$("#normalPriceContainer").hide();
}
}
function getParam(paramName) {
paramValue = "", isFound = !1;
if (this.location.search.indexOf("?") == 0 && this.location.search.indexOf("=") > 1) {
arrSource = unescape(this.location.search).substring(1, this.location.search.length).split("&"), i = 0;
while (i < arrSource.length && !isFound)
arrSource[i].indexOf("=") > 0 && arrSource[i].split("=")[0].toLowerCase() == paramName.toLowerCase() && (paramValue = arrSource[i].split("=")[1], isFound = !0), i++
}
return paramValue == "" && (paramValue = null), paramValue
}
script>
html>
在phantomjs/js/getitem.js中写入
var page = require("webpage").create();
var fs = require("fs");
page.open("http://seckillserver.psj14.com/resources/getitem.html?id=1",function(status) {
console.log("status = " + status);
var isInit = "0";
setInterval(function(){
if (isInit != "1") {
page.evaluate(function(){
initView();
});
isInit = page.evaluate(function(){
return hasInit();
});
}else{
fs.write("getitemphantom.html",page.content,"w");
phantom.exit();
}
},1000);
});
setInterval为定时器 设置每隔一秒执行一次
page.evaluate用于调用前端js中的initView()方法