擊右上方紅色按鈕關注“web秀”,讓你真正秀起來
前段時間寫過一篇《CSS3實現美美噠的圖片倒影效果》,里面最后一步,“我們使倒影傾斜一個角度,讓整個倒影效果更具有立體效果”,不知道大家有沒有聯想到用傾斜,我們可以制作一個立方體呢???
今天我們就來用純css制作一個立方體,主要用到的知識就是transform: rotate,沒有了解的可以點擊下方文章了解: 《CSS3中transition、transform傻傻分不清楚》
效果預覽圖:
CSS3實現3D水晶立方體效果
立方體,是由6個面組成的,所以我們主要是操作6個面,組合成一個立方體就可以實現。
觀察者方向的為z軸的正值方向
觀察者方向的為z軸的正值方向
rotateX 3D空間旋轉指定的角度,沿著垂直于X軸的方向順時針旋轉。 rotateY 3D空間旋轉指定的角度,沿著垂直于Y軸的方向順時針旋轉。 rotateZ 3D空間旋轉指定的角度,沿著垂直于Z軸的方向順時針旋轉。
CSS3實現3D水晶立方體效果
<div class="wrap"> <div class="cube"> <div class="before"></div> <div class="after"></div> </div> </div>
下面的樣式,我們對整個盒子沿著垂直于X軸的方向逆時針旋轉30°,Y軸逆時針旋轉80°,前面元素Z軸位移100px, 后面元素Z軸位移-100px,并Y軸順時針旋轉180°。讓效果看起來更明晰,有錯位立體感。
/*最外層容器樣式*/ .wrap{ width: 200px; height: 200px; margin: 150px auto; position: relative; } /*包裹所有容器樣式*/ .cube{ width: 200px; height: 200px; margin: 0 auto; /*preserve-3d 使其子元素具有3D效果*/ transform-style: preserve-3d; transform: rotateX(-30deg) rotateY(-80deg); } .cube div{ position: absolute; width: 200px; height: 200px; opacity: 0.8; } .cube .before{ transform: rotateY(0deg) translateZ(100px); background: red; } .cube .after{ transform: translateZ(-100px) rotateY(180deg); background: blue; }
和第一步類似,同樣旋轉和位移這兩個面,使其能夠完美拼接
CSS3實現3D水晶立方體效果
<div class="wrap"> <div class="cube"> <div class="before"></div> <div class="after"></div> <div class="right"></div> <div class="left"></div> </div> </div>
添加樣式
.cube .left{ transform: rotateY(90deg) translateZ(100px); background: green; } .cube .right{ transform: rotateY(-90deg) translateZ(100px); background: yellow; }
依次類推,完成上下2個面。
CSS3實現3D水晶立方體效果
<div class="wrap"> <div class="cube"> <div class="before"></div> <div class="after"></div> <div class="right"></div> <div class="left"></div> <div class="top"></div> <div class="bottom"></div> </div> </div>
添加樣式
.cube .top{ transform: rotateX(90deg) translateZ(100px); background: purple; } .cube .bottom{ transform: rotateX(-90deg) translateZ(100px); background: pink; }
我們給每個面添加一個背景圖片,然后讓整個盒子旋轉起來,使我們可以看到每個面的內容。
<div class="wrap"> <div class="cube"> <div class="before"> <img src="../images/20180801122834.png" class="pic" /> </div> <div class="after"> <img src="../images/20180911140432.png" class="pic" /> </div> <div class="right"> <img src="../images/20181025165730.png" class="pic" /> </div> <div class="left"> <img src="../images/20181026153658.png" class="pic" /> </div> <div class="top"> <img src="../images/20180911175248.png" class="pic" /> </div> <div class="bottom"> <img src="../images/20180801121251.png" class="pic" /> </div> </div> </div>
添加樣式
.pic{ width: 200px; height: 200px; } @-webkit-keyframes rotate{ from{ transform: rotateX(0deg) rotateY(0deg); } to{ transform: rotateX(360deg) rotateY(360deg); } } .cube{ width: 200px; height: 200px; margin: 0 auto; transform-style: preserve-3d; transform: rotateX(-30deg) rotateY(-80deg); -webkit-animation: rotate 20s infinite; animation-timing-function: linear; }
最終效果圖:
CSS3實現3D水晶立方體效果
喜歡小編的點擊關注,了解更多知識!
源碼地址請點擊下方“了解更多”
在日常開發中,我們經常會有格式化的需求,如日期格式化、數字格式化、錢幣格式化等等。
格式化器的作用似乎跟轉換器的作用類似,但是它們的關注點卻不一樣:
Spring有自己的格式化器抽象org.springframework.format.Formatter,但是談到格式化器,必然就會聯想起來JDK自己的java.text.Format體系。為后文做好鋪墊,本文就先介紹下JDK為我們提供了哪些格式化能力。
Java里從來都缺少不了字符串拼接的活,JDK也提供了多種“工具”供我們使用,如:StringBuffer、StringBuilder以及最直接的+號,相信這些大家都有用過。但這都不是本文的內容,本文將講解格式化器,給你提供一個新的思路來拼接字符串,并且是推薦方案。
JDK內置有格式化器,便是java.text.Format體系。它是個抽象類,提供了兩個抽象方法:
public abstract class Format implements Serializable, Cloneable {
public abstract StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
public abstract Object parseObject (String source, ParsePosition pos);
}
Java SE針對于Format抽象類對于常見的應用場景分別提供了三個子類實現:
抽象類。用于用于格式化日期/時間類型java.util.Date。雖然是抽象類,但它提供了幾個靜態方法用于獲取它的實例:
// 格式化日期 + 時間
public final static DateFormat getInstance() {
return getDateTimeInstance(SHORT, SHORT);
}
public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale){
return get(timeStyle, dateStyle, 3, aLocale);
}
// 格式化日期
public final static DateFormat getDateInstance(int style, Locale aLocale) {
return get(0, style, 2, aLocale);
}
// 格式化時間
public final static DateFormat getTimeInstance(int style, Locale aLocale){
return get(style, 0, 1, aLocale);
}
有了這些靜態方法,你可在不必關心具體實現的情況下直接使用:
/**
* {@link DateFormat}
*/
@Test
public void test1() {
Date curr = new Date();
// 格式化日期 + 時間
System.out.println(DateFormat.getInstance().getClass() + "-->" + DateFormat.getInstance().format(curr));
System.out.println(DateFormat.getDateTimeInstance().getClass() + "-->" + DateFormat.getDateTimeInstance().format(curr));
// 格式化日期
System.out.println(DateFormat.getDateInstance().getClass() + "-->" + DateFormat.getDateInstance().format(curr));
// 格式化時間
System.out.println(DateFormat.getTimeInstance().getClass() + "-->" + DateFormat.getTimeInstance().format(curr));
}
運行程序,輸出:
class java.text.SimpleDateFormat-->20-12-25 上午7:19
class java.text.SimpleDateFormat-->2020-12-25 7:19:30
class java.text.SimpleDateFormat-->2020-12-25
class java.text.SimpleDateFormat-->7:19:30
嗯,可以看到底層實現其實是咱們熟悉的SimpleDateFormat。實話說,這種做法不常用,狠一點:基本不會用(框架開發者可能會用做兜底實現)。
一般來說,我們會直接使用SimpleDateFormat來對Date進行格式化,它可以自己指定Pattern,個性化十足。如:
@Test
public void test2() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // yyyy-MM-dd HH:mm:ss
System.out.println(dateFormat.format(new Date()));
}
運行程序,輸出:
2020-12-25
關于SimpleDateFormat的使用方式不再啰嗦,不會的就可走自行勸退手續了。此處只提醒一點:SimpleDateFormat線程不安全。
說明:JDK 8以后不再建議使用Date類型,也就不會再使用到DateFormat。同時我個人建議:在項目中可強制嚴令禁用
抽象類。用于格式化數字,它可以對數字進行任意格式化,如小數、百分數、十進制數等等。它有兩個實現類:
類結構和DateFormat類似,也提供了getXXXInstance靜態方法給你直接使用,無需關心底層實現:
@Test
public void test41() {
double myNum = 1220.0455;
System.out.println(NumberFormat.getInstance().getClass() + "-->" + NumberFormat.getInstance().format(myNum));
System.out.println(NumberFormat.getCurrencyInstance().getClass() + "-->" + NumberFormat.getCurrencyInstance().format(myNum));
System.out.println(NumberFormat.getIntegerInstance().getClass() + "-->" + NumberFormat.getIntegerInstance().format(myNum));
System.out.println(NumberFormat.getNumberInstance().getClass() + "-->" + NumberFormat.getNumberInstance().format(myNum));
System.out.println(NumberFormat.getPercentInstance().getClass() + "-->" + NumberFormat.getPercentInstance().format(myNum));
}
運行程序,輸出:
class java.text.DecimalFormat-->1,220.045
class java.text.DecimalFormat-->¥1,220.05
class java.text.DecimalFormat-->1,220
class java.text.DecimalFormat-->1,220.045
class java.text.DecimalFormat-->122,005%
這一看就知道DecimalFormat是NumberFormat的主力了。
Decimal:小數,小數的,十進位的。
用于格式化十進制數字。它具有各種特性,可以解析和格式化數字,包括:西方數字、阿拉伯數字和印度數字。它還支持不同種類的數字,包括:整數(123)、小數(123.4)、科學記數法(1.23E4)、百分數(12%)和貨幣金額(3)。所有這些都可以進行本地化。
下面是它的構造器:
其中最為重要的就是這個pattern(不帶參數的構造器一般不會用),它表示格式化的模式/模版。一般來說我們對DateFormat的pattern比較熟悉,但對數字格式化的模版符號了解甚少。這里我就幫你整理出這個表格(信息源自JDK官網),記得收藏哦:
說明:Number和Digit的區別:
Number是個抽象概念,其表達形式可以是數字、手勢、聲音等等。如1024就是個numberDigit是用來表達的單獨符號。如0-9這是個digit就可以用來表示number,如1024就是由1、0、2、4這四個digit組成的
看了這個表格的符號規則,估計很多同學還是一臉懵逼。不啰嗦了,上干貨
這是最經典、最常見的使用場景,甚至來說你有可能職業生涯只會用到此場景。
/**
* {@link DecimalFormat}
*/
@Test
public void test4() {
double myNum = 1220.0455;
System.out.println("===============0的使用===============");
System.out.println("只保留整數部分:" + new DecimalFormat("0").format(myNum));
System.out.println("保留3位小數:" + new DecimalFormat("0.000").format(myNum));
System.out.println("整數部分、小數部分都5位。不夠的都用0補位(整數高位部,小數低位補):" + new DecimalFormat("00000.00000").format(myNum));
System.out.println("===============#的使用===============");
System.out.println("只保留整數部分:" + new DecimalFormat("#").format(myNum));
System.out.println("保留2為小數并以百分比輸出:" + new DecimalFormat("#.##%").format(myNum));
// 非標準數字(不建議這么用)
System.out.println("===============非標準數字的使用===============");
System.out.println(new DecimalFormat("666").format(myNum));
System.out.println(new DecimalFormat(".6666").format(myNum));
}
運行程序,輸出:
===============0的使用===============
只保留整數部分:1220
保留3位小數:1220.045
整數部分、小數部分都5位。不夠的都用0補位(整數高位部,小數低位補):01220.04550
===============#的使用===============
只保留整數部分:1220
保留2為小數并以百分比輸出:122004.55%
===============非標準數字的使用===============
661220
1220.666
通過此案例,大致可得出如下結論:
如果你不是在證券/銀行行業,這個大概率是用不著的(即使在,你估計也不會用它)。來幾個例子感受一把就成:
@Test
public void test5() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat("0E0").format(myNum));
System.out.println(new DecimalFormat("0E00").format(myNum));
System.out.println(new DecimalFormat("00000E00000").format(myNum));
System.out.println(new DecimalFormat("#E0").format(myNum));
System.out.println(new DecimalFormat("#E00").format(myNum));
System.out.println(new DecimalFormat("#####E00000").format(myNum));
}
運行程序,輸出:
1E3
1E03
12200E-00001
.1E4
.1E04
1220E00000
分組分隔符比較常用,它就是我們常看到的逗號,
@Test
public void test6() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat(",###").format(myNum));
System.out.println(new DecimalFormat(",##").format(myNum));
System.out.println(new DecimalFormat(",##").format(123456789));
// 分隔符,左邊是無效的
System.out.println(new DecimalFormat("###,##").format(myNum));
}
運行程序,輸出:
1,220
12,20
1,23,45,67,89
12,20
在展示層面也比較常用,用于把一個數字用%形式表示出來。
@Test
public void test42() {
double myNum = 1220.0455;
System.out.println("百分位表示:" + new DecimalFormat("#.##%").format(myNum));
System.out.println("千分位表示:" + new DecimalFormat("#.##\u2030").format(myNum));
}
運行程序,輸出:
百分位表示:122004.55%
千分位表示:1220045.5‰
嗯,這個符號¤,鍵盤竟無法直接輸出,得使用軟鍵盤(建議使用copy大法)。
@Test
public void test7() {
double myNum = 1220.0455;
System.out.println(new DecimalFormat(",000.00¤").format(myNum));
System.out.println(new DecimalFormat(",000.¤00").format(myNum));
System.out.println(new DecimalFormat("¤,000.00").format(myNum));
System.out.println(new DecimalFormat("¤,000.¤00").format(myNum));
// 世界貨幣表達形式
System.out.println(new DecimalFormat(",000.00¤¤").format(myNum));
}
運行程序,輸出:
1,220.05¥
1,220.05¥
¥1,220.05
1,220.05¥¥
¥1,220.05¥
1,220.05CNY
注意最后一條結果:如果連續出現兩次,代表貨幣符號的國際代號。
說明:結果默認都做了Locale本地化處理的,若你在其它國家就不會再是¥人民幣符號嘍
DecimalFormat就先介紹到這了,其實掌握了它就基本等于掌握了NumberFormat。接下來再簡要看看它另外一個“兒子”:ChoiceFormat。
Choice:精選的,仔細推敲的。
這個格式化器非常有意思:相當于以數字為鍵,字符串為值的鍵值對。使用一組double類型的數組作為鍵,一組String類型的數組作為值,兩數組相同(不一定必須是相同,見示例)索引值的元素作為一對。
@Test
public void test8() {
double[] limits = {1, 2, 3, 4, 5, 6, 7};
String[] formats = {"周一", "周二", "周三", "周四", "周五", "周六", "周天"};
NumberFormat numberFormat = new ChoiceFormat(limits, formats);
System.out.println(numberFormat.format(1));
System.out.println(numberFormat.format(4.3));
System.out.println(numberFormat.format(5.8));
System.out.println(numberFormat.format(9.1));
System.out.println(numberFormat.format(11));
}
運行程序,輸出:
周一
周四
周五
周天
周天
結果解釋:
可能你會想這有什么使用場景???是的,不得不承認它的使用場景較少,本文下面會介紹下它和MessageFormat的一個使用場景。
如果說DateFormat和NumberFormat都用沒什么花樣,主要記住它的pattern語法格式就成,那么就下來這個格式化器就是本文的主菜了,使用場景非常的廣泛,它就是MessageFormat。
MessageFormat提供了一種與語言無關(不管你在中國還是其它國家,效果一樣)的方式生成拼接消息/拼接字符串的方法。使用它來構造顯示給最終用戶的消息。MessageFormat接受一組對象,對它們進行格式化,然后在模式的適當位置插入格式化的字符串。
先來個最簡單的使用示例體驗一把:
/**
* {@link MessageFormat}
*/
@Test
public void test9() {
String sourceStrPattern = "Hello {0},my name is {1}";
Object[] args = new Object[]{"girl", "YourBatman"};
String formatedStr = MessageFormat.format(sourceStrPattern, args);
System.out.println(formatedStr);
}
運行程序,輸出:
Hello girl,my name is YourBatman
有沒有中似曾相似的感覺,是不是和String.format()的作用特別像?是的,它倆的用法區別,到底使用稅文下也會討論。
要熟悉MessageFormat的使用,主要是要熟悉它的參數模式(你也可以理解為pattern)。
MessageFormat采用{}來標記需要被替換/插入的部分,其中{}里面的參數結構具有一定模式:
ArgumentIndex[,FormatType[,FormatStyle]]
說明:FormatType和FormatStyle只有在傳入值為日期時間、數字、百分比等類型時才有可能需要設置,使用得并不多。畢竟:我在外部格式化好后再放進去不香嗎?
@Test
public void test10() {
MessageFormat messageFormat = new MessageFormat("Hello, my name is {0}. I’am {1,number,#.##} years old. Today is {2,date,yyyy-MM-dd HH:mm:ss}");
// 亦可通過編程式 顯示指定某個位置要使用的格式化器
// messageFormat.setFormatByArgumentIndex(1, new DecimalFormat("#.###"));
System.out.println(messageFormat.format(new Object[]{"YourBatman", 24.123456, new Date()}));
}
運行程序,輸出:
Hello, my name is YourBatman. I’am 24.12 years old. Today is 2020-12-26 15:24:28
它既可以直接在模版里指定格式化模式類型,也可以通過API方法set指定格式化器,當然你也可以在外部格式化好后再放進去,三種方式均可,任君選擇。
下面基于此示例,對MessageFormat的使用注意事項作出幾點強調。
@Test
public void test11() {
System.out.println(MessageFormat.format("{1} - {1}", new Object[]{1})); // {1} - {1}
System.out.println(MessageFormat.format("{0} - {1}", new Object[]{1})); // 輸出:1 - {1}
System.out.println(MessageFormat.format("{0} - {1}", new Object[]{1, 2, 3})); // 輸出:1 - 2
System.out.println("---------------------------------");
System.out.println(MessageFormat.format("'{0} - {1}", new Object[]{1, 2})); // 輸出:{0} - {1}
System.out.println(MessageFormat.format("''{0} - {1}", new Object[]{1, 2})); // 輸出:'1 - 2
System.out.println(MessageFormat.format("'{0}' - {1}", new Object[]{1, 2})); // {0} - 2
// 若你數據庫值兩邊都需要''包起來,請你這么寫
System.out.println(MessageFormat.format("''{0}'' - {1}", new Object[]{1, 2})); // '1' - 2
System.out.println("---------------------------------");
System.out.println(MessageFormat.format("0} - {1}", new Object[]{1, 2})); // 0} - 2
System.out.println(MessageFormat.format("{0 - {1}", new Object[]{1, 2})); // java.lang.IllegalArgumentException: Unmatched braces in the pattern.
}
我們知道MessageFormat提供有一個static靜態方法,非常方便地的使用:
public static String format(String pattern, Object ... arguments) {
MessageFormat temp = new MessageFormat(pattern);
return temp.format(arguments);
}
可以清晰看到,該靜態方法本質上還是構造了一個MessageFormat實例去做格式化的。因此:若你要多次(如高并發場景)格式化同一個模版(參數可不一樣)的話,那么提前創建好一個全局的(非static) MessageFormat實例再執行格式化是最好的,而非一直調用其靜態方法。
說明:若你的系統非高并發場景,此性能損耗基本無需考慮哈,怎么方便怎么來。畢竟朝生夕死的對象對JVM來說沒啥壓力
二者都能用于字符串拼接(格式化)上,撇開MessageFormat支持各種模式不說,我們只需要考慮它倆的性能上差異。
一說到正則表達式,我心里就發怵,因為它對性能是不友好的,所以孰優孰劣,高下立判。
說明:還是那句話,沒有絕對的誰好誰壞,如果你的系統對性能不敏感,那就是方便第一
這個就很多啦,最常見的有:HTML拼接、SQL拼接、異常信息拼接等等。
比如下面這個SQL拼接:
StringBuilder sb =new StringBuilder();
sb.append("insert into user (");
sb.append(" name,");
sb.append(" accountId,");
sb.append(" zhName,");
sb.append(" enname,");
sb.append(" status");
sb.append(") values (");
sb.append(" ''{0}'',");
sb.append(" {1},");
sb.append(" ''{2}'',");
sb.append(" ''{3}'',");
sb.append(" {4},");
sb.append(")");
Object[] args = {name, accountId, zhName, enname, status};
// 最終SQL
String sql = MessageFormat.format(sb.toString(), arr);
你看,多工整。
說明:如果值是字符串需要'包起來,那么請使用兩邊各兩個包起來
本文內容介紹了JDK原生的格式化器知識點,主要作用在這三個方面:
Spring是直接面向使用者的框架產品,很顯然這些是不夠用的,并且JDK的格式化器在設計上存在一些弊端。比如經常被吐槽的:日期/時間類型格式化器SimpleDateFormat為毛在java.text包里,而它格式化的類型Date卻在java.util包內,這實為不合適。
有了JDK格式化器作為基礎,下篇我們就可以浩浩蕩蕩地走進Spring格式化器的大門了,看看它是如何優于JDK進行設計和抽象的。
作者:YourBatman
原文鏈接:https://fangshixiang.blog.csdn.net/article/details/111752597
EO優化公司:網站緩存策略,今天小編要和大家說說,網站緩存策略,什么是網站緩存相信大家并不陌生,就是cookie,廣州百度SEO公司越視界將從技術角度為大家揭秘網站緩存策略秘密。
在這《廣州百度SEO優化公司:網站緩存策略》文章中,我們將討論一些Web內容緩存的基本概念。這主要包括如何選擇緩存策略以保證互聯網范圍內的緩存能夠正確的處理您的內容。我們將談一談緩存帶來的好處、副作用以及不同的策略能帶來的性能和靈活性的最大結合。
[caption id="attachment_4765" align="aligncenter" width="600"]
廣州百度SEO優化公司:網站緩存策略[/caption]
什么是緩存(caching)?
緩存(caching)是一個描述存儲可重用資源以便加快后續請求的行為的術語。有許多不同類型的緩存,每種都有其自身的特點,應用程序緩存和內存緩存由于其對特定回復的加速,都很常用。
《廣州百度SEO優化公司:網站緩存策略》文章中的主要講述的Web緩存是一種不同類型的緩存。Web緩存是HTTP協議的一個核心特性,它能最小化網絡流量,并且提升用戶所感知的整個系統響應速度。內容從服務器到瀏覽器的傳輸過程中,每個層面都可以找到緩存的身影。
Web緩存根據特定的規則緩存相應HTTP請求的響應。對于緩存內容的后續請求便可以直接由緩存滿足而不是重新發送請求到Web服務器。
好處
有效的緩存技術不僅可以幫助用戶,還可以幫助內容的提供者。緩存對內容分發帶來的好處有:
●減少網絡開銷:內容可以在從內容提供者到內容消費者網絡路徑之間的許多不同的地方被緩存。當內容在距離內容消費者更近的地方被緩存時,由于緩存的存在,請求將不會消耗額外的網絡資源。
●加快響應速度:由于并不是必須通過整個網絡往返,緩存可以使內容的獲得變得更快。緩存放在距用戶更近的地方,例如瀏覽器緩存,使得內容的獲取幾乎是瞬時的。
●在同樣的硬件上提高速度:對于保存原始內容的服務器來說,更多的性能可以通過允許激進的緩存策略從硬件上壓榨出來。內容擁有者們可以利用分發路徑上某個強大的服務器來應對特定內容負載的沖擊。
●網絡中斷時內容依舊可用:使用某種策略,緩存可以保證在原始服務器變得不可用時,相應的內容對用戶依舊可用。
什么能被緩存?
某些特定的內容比其他內容更容易被緩存。對大多數站點來說,一些適合緩存的內容如下:
●Logo和商標圖像
●普通的不變化的圖像(例如,導航圖標)
●CSS樣式表
●普通的Java文件
●可下載的內容
●媒體文件
這些文件更傾向于不經常改變,所以長時間的對它們進行緩存能獲得好處。
一些項目在緩存中必須加以注意:
●HTML頁面
●會替換改變的圖像
●經常修改的Java和CSS文件
●需要有認證后的cookies才能訪問的內容
一些內容從來不應該被緩存:
●與敏感信息相關的資源(銀行數據,等)
●用戶相關且經常更改的數據
除上面的通用規則外,通常您需要指定一些規則以便于更好地緩存不同種類的內容。例如,如果登錄的用戶都看到的是同樣的網站視圖,就應該在任何地方緩存這個頁面。如果登錄的用戶會在一段時間內看到站點中用戶特定的視圖,您應該讓用戶的瀏覽器緩存該數據而不應讓任何中介節點緩存該視圖。
Web內容緩存的位置
Web內容會在整個分發路徑中的許多不同的位置被緩存:
●瀏覽器緩存:Web瀏覽器自身會維護一個小型緩存。典型地,瀏覽器使用一種策略指示緩存最重要的內容。這可能是用戶相關的內容或可能會再次請求且下載代價較高。
●中間緩存代理:任何在客戶端和您的基礎架構之間的服務器都可以按期望緩存一些內容。這些緩存可能由ISP(網絡服務提供者)或者其他獨立組織提供。
●反向緩存:您的服務器基礎架構可以為后端的服務實現自己的緩存。如果實現了緩存,那么便可以在處理請求的位置返回相應的內容而不用每次請求都使用后端服務。
上面的這些位置通常都可以根據它們自身的緩存策略和內容源的緩存策略緩存一些相應的內容。
一些您可以使用的指示內容緩存策略的Cache-Control的選項如下:
●no-cache:這個指令指示所有緩存的內容在新的請求到達時必須先重新驗證,再發送給客戶端。這條指令實際將內容立刻標記為過期的,但允許通過驗證手段重新驗證以避免重新下載整個內容。
●no-store:這條指令指示緩存的內容不能以任何方式被緩存。它適合在回復敏感信息時設置。
●public:它將內容標記為公有的,這意味著它能被瀏覽器和其他任何中間節點緩存。通常,對于使用了HTTP驗證的請求,其回復被默認標記為private。public標記將會覆蓋這個設置。
●private:它將內容標記為私有的。私有數據可以被用戶的瀏覽器緩存,但不能被任何中間節點緩存。它通常用于用戶相關的數據。
●max-age:這個設置指示了緩存內容的最大生存期,它在最大生存期后必須在源服務器處被驗證或被重新下載。在現代瀏覽器中這個選項大體上取代了Expires頭部,瀏覽器也將其作為決定內容的新鮮度的基礎。這個選項的值以秒為單位表示,最大可以表示一年的新鮮期(31536000秒)。
●s-maxage:這個選項非常類似于max-age,它指明了內容能夠被緩存的時間。區別是這個選項只在中間節點的緩存中有效。結合這兩個選項可以構建更加靈活的緩存策略。
●must-revalidate:它指明了由max-age、s-maxage或Expires頭部指明的新鮮度信息必須被嚴格的遵守。它避免了緩存的數據在網絡中斷等類似的場景中被使用。
●proxy-revalidate:它和上面的選項有著一樣的作用,但只應用于中間的代理節點。在這種情況下,用戶的瀏覽器可以在網絡中斷時使用過期內容,但中間緩存內容不能用于此目的。
●no-transform:這個選項告訴緩存在任何情況下都不能因為性能的原因修改接收到的內容。這意味著,緩存不允許壓縮接收到的內容(沒有從原始服務器處接收過壓縮版本的該內容)并發送。
這些選項能夠以不同的方式結合以獲得不同的緩存行為。一些互斥的值如下:
●no-cache,no-store以及由其他前面未提到的選項指明的常用的緩存行為
●public和private
如果no-store和no-cache都被設置,那么no-store會取代no-cache。對于非授權的請求的回復,public是隱含的設置。對于授權的請求的回復,private選項是隱含的。他們可以通過在Cache-Control頭部中指明相應的相反的選項以覆蓋。
開發一種緩存策略
在理想情況下,任何內容都可以被盡可能緩存,而您的服務器只需要偶爾的提供一些驗證內容即可。但這在現實中很少發生,因此您應該嘗試設置一些明智的緩存策略,以在長期緩存和站點改變的需求間達到平衡。
常見問題
在許多情況中,由于內容被產生的方式(如根據每個用戶動態的產生)或者內容的特性(例如銀行的敏感數據),這些內容不應該被緩存。另一些許多管理員在設置緩存時可能面對的問題是外部緩存的數據未過期,但新版本的數據已經產生。
這些都是經常遇到的問題,它們會影響緩存的性能和您提供的數據的準確性。然而,我們可以通過開發提前預見這些問題的緩存策略來緩解這些問題。
一般性建議
盡管您的實際情況會指導您選擇的緩存策略,但是下面的建議能幫助您獲得一些合理的決定。
在您擔心使用哪一個特定的頭部之前,有一些特定的步驟可以幫助您提高您的緩存命中率。一些建議如下:
●為圖像、CSS和共享的內容建立特定的文件夾:將內容放到特定的文件夾內使得您可以方便的從您的站點中的任何頁面引用這些內容。
●使用同樣的URL來表示同樣的內容:由于緩存使用內容請求中的主機名和路徑作為鍵,因此應保證您的所有頁面中的該內容的引用方式相同,前一個建議能讓這點更加容易做到。
●盡可能使用CSS圖像拼接:對于像圖標和導航等內容,使用CSS圖像拼接能夠減少渲染您頁面所需要的請求往返,并且允許對拼接緩存很長一段時間。
●盡可能將主機腳本和外部資源本地化:如果您使用Java腳本和其他外部資源,如果上游沒有提供合適的緩存頭部,那么您應考慮將這些內容放在您自己的服務器上。您應該注意上游的任何更新,以便更新本地的拷貝。
●對緩存內容收集文件摘要:靜態的內容比如CSS和Java文件等通常比較適合收集文件摘要。這意味著為文件名增加一個獨特的標志符(通常是這個文件的哈希值)可以在文件修改后繞開緩存保證新的內容被重新獲取。有很多工具可以幫助您創建文件摘要并且修改HTML文檔中的引用。
對于不同的文件正確地選擇不同的頭部這件事,下面的內容可以作為一般性的參考:
●允許所有的緩存存儲一般內容:靜態內容以及非用戶相關的內容應該在分發鏈的所有節點被緩存。這使得中間節點可以將該內容回復給多個用戶。
●允許瀏覽器緩存用戶相關的內容:對于每個用戶的數據,通常在用戶自己的瀏覽器中緩存是可以被接受且有益的。緩存在用戶自身的瀏覽器能夠使得用戶在接下來的瀏覽中能夠瞬時讀取,但這些內容不適合在任何中間代理節點緩存。
●將時間敏感的內容作為特例:如果您的數據是時間敏感的,那么相對上面兩條參考,應該將這些數據作為特例,以保證過期的數據不會在關鍵的情況下被使用。例如,您的站點有一個購物車,它應該立刻反應購物車里面的物品。依據內容的特點,可以在Cache-Control頭部中使用no-cache或no-store選項。
●總是提供驗證器:驗證器使得過期的內容可以無需重新下載而得到刷新。設置ETag和Last-Modified頭部將允許緩存向原始服務器驗證內容,并在內容未修改時刷新該內容新鮮度以減少負載。
●對于支持的內容設置長的新鮮期:為了更加有效的利用緩存,一些作為支持性的內容應該被設置較長的新鮮期。這通常比較適合圖像和CSS等由用戶請求用來渲染HTML頁面的內容。和文件摘要一起,設置延長的新鮮期將允許緩存長時間的存儲這些資源。如果資源發生改變,修改的文件摘要將會使緩存的數據無效并觸發對新的內容的下載。那時,新的支持的內容會繼續被緩存。
●對父內容設置短的新鮮期:為了使得前面的模式正常工作,容器類的內容應該相應的設置短的新鮮期,或者設置不全部緩存。這通常是在其他協助內容中使用的HTML頁面。這個HTML頁面將會被頻繁的下載,使得它能快速的響應改變。支持性的內容因此可以被盡量緩存。
關鍵之處便在于達到平衡,一方面可以盡量的進行緩存,另一方面為未來保留當改變發生時從而改變整個內容的機會。您的站點應該同時具有:
●盡量緩存的內容
●擁有短的新鮮期的緩存內容,可以被重新驗證
●完全不被緩存的內容
這樣做的目的便是將內容盡可能的移動到第一個分類(盡量緩存)中的同時,維持可以接受的緩存命中率。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。