1.1.1 摘要
CDN相信大家都聽(tīng)說(shuō)過(guò),甚至使用過(guò)相關(guān)的技術(shù),也許有些人會(huì)回答“沒(méi)有聽(tīng)說(shuō)過(guò)和使用過(guò)該技術(shù)”,真的是這樣嗎?
CDN的全稱是Content Delivery Network烹吵,即內(nèi)容分發(fā)網(wǎng)絡(luò)。其目的是通過(guò)在現(xiàn)有的Internet中增加一層新的網(wǎng)絡(luò)架構(gòu)桨武,將網(wǎng)站的內(nèi)容發(fā)布到最接近用戶的網(wǎng)絡(luò)"邊緣"肋拔,使用戶可以就近取得所需的內(nèi)容,解決 Internet網(wǎng)絡(luò)擁擠的狀況呀酸,提高用戶訪問(wèn)網(wǎng)站的響應(yīng)速度凉蜂。
看完上面一大串的定義,我們可以把CDN簡(jiǎn)單的描述為:內(nèi)容分發(fā)性誉,解決網(wǎng)絡(luò)擁擠和提供網(wǎng)站相應(yīng)速度窿吩。
其實(shí),CDN并不神秘甚至我們?cè)谌粘i_(kāi)發(fā)過(guò)程中常常使用到該技術(shù)错览,例如:引用網(wǎng)絡(luò)腳本庫(kù)(如:jQuery)和網(wǎng)絡(luò)圖片資源等纫雁。
我們經(jīng)常發(fā)現(xiàn)許多網(wǎng)站都從Google的CDN中引用相應(yīng)的Javascript庫(kù),但很多網(wǎng)站都沒(méi)有考慮如果CDN內(nèi)容加載失敗的情況倾哺,我們并不是說(shuō)Google的CDN很脆弱轧邪,只是不怕萬(wàn)一只怕一萬(wàn)。
在接下來(lái)的博文中悼粮,我們將想大家介紹防范CDN內(nèi)容加載的方法闲勺。
目錄
- 基本方法
- HTML5 Boilerplate中的解決方法
- Javascript加載器
- ASP.NET Web Form 4.5
- AspNet.ScriptManager.jQuery包
- ASP.NET Web Optimization包
1.1.2 正文
基本方法
檢查CDN內(nèi)容是否加載成功的基本的方法,我們可以在腳本代碼后添加代碼判斷該類型或變量是否存在扣猫,如果不存證明CDN加載失敗,那么我們的程序就應(yīng)該加載本地腳本翘地,下面我們以加載jQuery庫(kù)為例申尤,具體實(shí)現(xiàn)如下:
<!-- Adds google cdn reference -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<!-- Cdn fail refers to local library -->
<script type="text/javascript">
if (typeof jQuery == 'undefined') {
document.write(unescape("%3Cscript src='js/jquery-2.0.0.min.js' type='text/javascript'%3E%3C/script%3E"));
}
</script>
上面,我們引用了 Google CDN 的jQuery庫(kù)衙耕,接著我們?cè)谀_本代碼后添加了一個(gè) if 語(yǔ)句來(lái)判斷 jQuery 庫(kù)是否加載成功昧穿,如果沒(méi)有加載成功我們動(dòng)態(tài)加載本地 jQuery 庫(kù)。
其中橙喘,我們?cè)?document.write 方法中直接使用了URL編碼时鸵,把“<”編碼為“%3C”,接著我們?cè)偈褂?unescape() 方法把字符串還原過(guò)來(lái)。
上圖饰潜,我們通過(guò) unescape() 方法把字符串轉(zhuǎn)換回來(lái)初坠,我們可以看到輸出是一個(gè)正常的腳本引用代碼。
現(xiàn)在彭雾,我們有一個(gè)疑問(wèn)就是“為什么不使用常規(guī)字符碟刺,而是要使用字符編碼呢?”薯酝,其實(shí)這是有原因的半沽,這意味著我們代碼將可以在XML、XHTML或HTML中正常運(yùn)行吴菠,而無(wú)需把代碼包含在 CDATA 中(具體請(qǐng)參考這里)者填。
HTML5 Boilerplate中的解決方法
接下來(lái),我們將介紹使用“協(xié)議省略”的引用地址和簡(jiǎn)化本地加載代碼做葵,在介紹之前占哟,首先讓我們了解使用“協(xié)議省略”的引用地址的優(yōu)點(diǎn)。
我們知道使用安全的引用地址對(duì)于確保信息安全是無(wú)可厚非的蜂挪,但過(guò)度地使用SSL緩存靜態(tài)資源例如:jQuery庫(kù)重挑,也會(huì)導(dǎo)致加載的性能降低;出于同樣的原因?yàn)g覽器需要對(duì)這些資源進(jìn)行加密棠涮,而且大多數(shù)瀏覽器默認(rèn)不緩存通過(guò)SSL方式獲取的文件谬哀。
更糟糕的是,即使用戶已經(jīng)有一個(gè)本地緩存副本在磁盤(pán)上严肪,但通過(guò)HTTP請(qǐng)求從Google的CDN獲取jQuery文件史煎,不能被同一請(qǐng)求不同協(xié)議HTTPS使用,也就是說(shuō)驳糯,對(duì)于同一請(qǐng)求不同協(xié)議要保存兩個(gè)緩存文件篇梭。
Http請(qǐng)求的URL地址:
http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js
下面是使用Https請(qǐng)求的URL地址:
https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js
當(dāng)我們?cè)诔R?guī)的Http頁(yè)面中通過(guò)Https方式來(lái)引用Google CDN的jQuery庫(kù)將導(dǎo)致緩存性能下降,我們應(yīng)該盡量避免在Http頁(yè)面中引用不必要的Https內(nèi)容酝枢。
在RFC3986中的第4.2節(jié)規(guī)定合法的URL省略了協(xié)議(Http或Http)還是合法的恬偷,當(dāng)一個(gè)URL的協(xié)議被省略時(shí),瀏覽器將使用基本的文檔的協(xié)議帘睦,通過(guò)這種方式袍患,我們可以更加靈活地指定URL地址。所以我們可以通過(guò)以下的方式引用jQuery庫(kù)竣付。
<!-- Adds protocol-less google cdn reference -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
上面的代碼看起來(lái)奇怪诡延,但“協(xié)議省略”的網(wǎng)址是引用第三方內(nèi)容的最好的方式,它可以通過(guò)Http或Https引用古胆。
當(dāng)頁(yè)面加載時(shí)肆良,對(duì)于非加密請(qǐng)求腳本會(huì)通過(guò)Http方式引用并且緩存起來(lái),以此同時(shí)對(duì)于加密請(qǐng)求腳本會(huì)根據(jù)“協(xié)議省略”方式使用Https引用內(nèi)容,所以使用“協(xié)議省略”的URL允許單個(gè)腳本更靈活地引用內(nèi)容惹恃。
接下來(lái)夭谤,我們繼續(xù)簡(jiǎn)化加載本地腳本的代碼,當(dāng)jQuery成功加載到頁(yè)面中座舍,它會(huì)創(chuàng)建一個(gè)全局的jQuery變量沮翔,我們可以通過(guò)window的jQuery屬性(window.jQuery)訪問(wèn)該變量的值,如果jQuery沒(méi)有加載成功曲秉,那么window.jQuery就是未定義的采蚀。
所以,我們可以把代碼簡(jiǎn)化成如下:
<!-- Adds protocol-less google cdn reference -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<!--<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js"></script>-->
<script>window.jQuery || document.write('<script src="js/jquery-2.0.0.min.js">\x3C/script>')</script>
上面承二,我們使用了“||”運(yùn)算符判斷window.jQuery是否為未定義類型榆鼠,如果 window.jQuery 未定義執(zhí)行后面的代碼加載本地jQuery腳本,HTML5 Boilerplate 就使用以上的方法處理CDN內(nèi)容加載失敗的情況亥鸠。
Javascript加載器
有些人使用JavaScript加載器如:yepnope妆够,它是一個(gè)能夠根據(jù)輸入條件來(lái)選擇性異步加載資源文件的js腳本,可以在頁(yè)面上僅加載用戶需要的js或css负蚊,下面我們以加載jQuery為例子介紹yepnope的使用神妹,具體實(shí)現(xiàn)如下:
yepnope([{
load: 'http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js',
complete: function () {
if (!window.jQuery) {
yepnope('js/jquery-2.0.0.min.js');
}
}
}]);
上面,我們使用加載器 yepnope 把 jQuery 加載到頁(yè)面中家妆,接下來(lái)鸵荠,我們介紹使用 RequireJS 加載 jQuery,具體實(shí)現(xiàn)如下:
// Uses requestJS to add cdn reference.
requirejs.config({
enforceDefine: true,
paths: {
jquery: [
'//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js',
//If the CDN location fails, load from this location
'js/jquery-2.0.0.min'
]
}
});
//Later
require(['jquery'], function($) {
// Your code here.
});
我們可以RequireJS加載器中使用“協(xié)議省略”的URL地址伤极,這樣我們可以避免前面提到的加密協(xié)議和非加密協(xié)議加密和緩存問(wèn)題了蛹找。
雖然,JS加載器也可以解決CDN內(nèi)容加載失敗的問(wèn)題哨坪,但僅僅為了防止CDN內(nèi)容加載失敗問(wèn)題而引入yepnope 或 RequireJS是沒(méi)有必要的庸疾。
ASP.NET Web Form 4.5
對(duì)于每個(gè)ASP.NET Web窗體開(kāi)發(fā)人員牵敷,我們需要了解在ASP.NET 4.5增加的新特性绝骚,其中就包含了處理CDN內(nèi)容加載失敗轉(zhuǎn)移加載本地內(nèi)容的特性挖函。
首先旭绒,我們?cè)陧?yè)面中添加ScriptManager控件,然后設(shè)置該控制的EnableCdn屬性為“True”犀填,接著我們添加需要加載的內(nèi)容名稱隐岛,下面以加載jQuery為例:
<!-- Set up cdn -->
<asp:ScriptManager runat="server" EnableCdn="true">
<Scripts>
<asp:ScriptReference Name="jquery" />
</Scripts>
</asp:ScriptManager>
上面螺垢,我們通過(guò) ScriptManager 控件指定加載 jQuery庫(kù)牵舱,但這里我們有一個(gè)疑問(wèn)首先是我們沒(méi)有指定加載 jQuery庫(kù)的URL地址,第二在加載失敗后缺虐,沒(méi)有指定本地 jQuery庫(kù)路徑芜壁。
現(xiàn)在,我們通過(guò)運(yùn)行頁(yè)面代碼查看 ScriptManager 生成的腳步代碼,具體代碼如下:
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
(window.jQuery) || document.write('<script type="text/javascript" src="Scripts/jquery-1.8.2.js"><\/script>'); //]]>
</script>
通過(guò)上面的代碼慧妄,我們發(fā)現(xiàn)ScriptManager默認(rèn)加載jQuery庫(kù)的URL是 http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.js 而且一旦加載失敗它自動(dòng)到Scripts文件中加載本地腳步顷牌。
雖然這種方式簡(jiǎn)單而且省心,但它默認(rèn)是到微軟的CDN中加載內(nèi)容的塞淹,如果我們想使用Google的CDN呢窟蓝?難道微軟打算CDN也搞壟斷嗎?還有我們想使用jQuery 2.0.0庫(kù)應(yīng)該如何加載呢饱普?
其實(shí)运挫,我們可以通過(guò)自定義 ScriptResourceMapping 方式來(lái)指定加載的 CDN和 jQuery庫(kù),我們要在 Global.asax 文件中添加以下代碼:
var mapping = ScriptManager.ScriptResourceMapping;
// Map jquery definition to the Google CDN
mapping.AddDefinition("jquery", new ScriptResourceDefinition
{
Path = "~/Scripts/jquery-2.0.0.min.js",
DebugPath = "~/Scripts/jquery-2.0.0.js",
CdnPath = "http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js",
CdnDebugPath = "https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.js",
CdnSupportsSecureConnection = true,
LoadSuccessExpression = "window.jQuery"
});
上面套耕,我們定義了加載 Google的 CDN和 jQuery 2.0.0版本谁帕,接下來(lái)我們重新運(yùn)行頁(yè)面代碼查看 ScriptManager生成的腳步代碼是否對(duì)應(yīng)我們的設(shè)置。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
(window.jQuery) || document.write('<script type="text/javascript" src="Scripts/jquery-2.0.0.js"><\/script>'); //]]>
</script>
現(xiàn)在冯袍,我們看到使用的是Google的CDN匈挖,并且加載jQuery的版本為2.0.0的。
AspNet.ScriptManager.jQuery包
在ASP.NET4.5中康愤,如果我們想使用jQuery 2.0.0或更新的版本儡循,其實(shí)我們可以通過(guò)使用AspNet.ScriptManager.jQuery包來(lái)管理引用庫(kù)的更新,其中它也包括配置CDN信息的功能征冷,如果我們要獲取最新的更新择膝,首先我們選擇工具->擴(kuò)展工具管理器->AspNet.ScriptManager.jQuery,然后更新包就可以獲取最新的jQuery庫(kù)资盅。
ASP.NET Web Optimization包
如果我們使用的是ASP.NET MVC程序调榄,同樣我們可以通過(guò)更新ASP.NET Web Optimization包來(lái)管理CDN配置信息。
接下來(lái)呵扛,我們?cè)诘?BundleConfig 中指定我們的 CdnPath 的 URL 地址每庆,打開(kāi) App_Start\BundleConfig.cs,我們可以看到里面有一個(gè) RegisterBundles() 方法今穿,下面是 RegisterBundles() 方法的一部分代碼:
/// <summary>
/// Sets up the jquery libs load path.
/// </summary>
/// <param name="bundles"></param>
public static void RegisterBundles(BundleCollection bundles)
{
bundles.UseCdn = true;
BundleTable.EnableOptimizations = true; //force optimization while debugging
var jquery = new ScriptBundle("~/bundles/jquery", "http://ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js").Include(
"~/Scripts/jquery-{version}.js");
jquery.CdnFallbackExpression = "window.jQuery";
bundles.Add(jquery);
//...
}
1.1.3 總結(jié)
在本文中缤灵,我們向大家介紹了一些 CDN 內(nèi)容引用失敗的處理機(jī)制,就處理方式來(lái)說(shuō)蓝晒,我覺(jué)得 HTML5 Boilerplate 的解決方法不但簡(jiǎn)潔腮出,而且不用引入第三方庫(kù)。
同時(shí)我們也介紹了使用“協(xié)議省略”的 CDN 的優(yōu)點(diǎn)芝薇,但有一點(diǎn)我們要注意的胚嘲,如果我們?cè)诒镜剡\(yùn)行使用“協(xié)議省略”的 URL 可能不會(huì)得到如預(yù)期運(yùn)行效果,由于我們?cè)诒镜剡\(yùn)行頁(yè)面“協(xié)議省略”使用的基礎(chǔ)協(xié)議是 file洛二,而不是 http 或 https馋劈,所以一般來(lái)說(shuō)我們?cè)诒镜刂苯舆\(yùn)行頁(yè)面是無(wú)法正確獲取到 CDN 的內(nèi)容攻锰,我們可以把頁(yè)面放到本地Web服務(wù)器中運(yùn)行,如 Apache 或IIS中妓雾,然后運(yùn)行 http://localhost的地址就可以加載成功了娶吞。
參考
http://www.hanselman.com/blog/CDNsFailButYourScriptsDontHaveToFallbackFromCDNToLocalJQuery.aspx
http://encosia.com/cripple-the-google-cdns-caching-with-a-single-character/
https://developers.google.com/speed/libraries/devguide
原著:JK_Rush 原文鏈接:引用CDN內(nèi)容的方法總結(jié)