用CDNs和Expires改善網站性能(譯文)

  已經有很多文章寫過使用CDN(Content Delivery Network,內容交付網絡)來實現靜態內容(JQuery,images,CSS文件等)的優點了。(如果你還不熟悉CNDs,請看這篇Microsoft AJAX CDN博客,英文版Announcing the Microsoft AJAX CDNMicrosoft Ajax Content Delivery Network),但是CNDs最大的優勢經常被忽視:

  • 許多主要的站點都是用CDN,所以很有可能你的客戶瀏覽器緩存已經包含了來自CDN的JQuery。當另一個站點要從Microsoft CDN加載一個JQuery版本的時候,但是如果你的客戶端緩存的JQuery版本滿足這個請求,這樣就不會再去Microsoft CDN重新下載。
  • 一旦內容從CDN中加載,如果內容是當前存在的,將來的請求不會引起與服務器的往返開銷(即不會再向服務器發送請求),也就是說,客戶端避免了HTTP 304。
  • 服務器集羣不需要協調ETag緩存驗證。

  下面將會用Fiddler工具和MVC電影示例來說明使用CDN的優勢。

  快速瀏覽瀏覽器緩存

  瀏覽器緩存有兩種主要機制:

  • 在瀏覽器緩存中驗證所請求的資源與服務器上是相同的。如果資源是相同的,服務器會返回一個HTTP 304響應,從而避免發送響應主體與內容的需要。許多人認爲HTTP 304是一件好事,因爲他們不需要發送一個完整的響應體。我將展示它們(HTTP 304響應)通常是對性能的拖累,因爲這涉及到和服務器不必要的往返。
  • 保鮮(Freshness):如果緩存中的資源是新的(fresh),則直接從緩存中提取資源不需要校驗服務器。

  瀏覽器使用一種新鮮的啓發式(freshness heuristic)來確定是否應該用服務器驗證資源還是從緩存中獲取資源、如果你清楚瀏覽器緩存,然後點擊我的電影示例,將會下載幾個靜態文件到客戶端緩存(JavaScript,CSS和images)。用IE9,Chrome和Firefox,你可以在接下來的幾天裏點擊電影網站,瀏覽器會從瀏覽器的特定緩存中換區這些文件作爲服務,甚至不需要檢查服務器。瀏覽器將緩存這些靜態文件,而不需要對服務器進行驗證,除非下面的幾種情況有一條爲true。

  • 不滿足新鮮啓發式(freshness heuristic)(也就是說,緩存中的文件不被認爲是最新的)。
  • 你已經更改了過期頭(expires header)或其他緩存頭。
  • 你已經設置了瀏覽器禁用緩存(caching)。
  • 資源更改了或者URL不同了。例如,下面的URL都是指向相同的modernizr腳本,但是因爲每個URL是不同的,所以必須下載每個資源。

  第一個和最後一個modernizer文件時由Cassini(默認的Visual Studio Web服務器)或是IIS Express服務器提供的,這就是爲什麼我們會看到端口號。中間的兩個文件是由本機器IIS服務器提供的,但是使用了兩個不同的主機名(localserver和實際名稱q1)。你可以通過在General選項卡上選擇瀏覽歷史記錄下的設置按鈕,然後選擇視圖文件來檢查IE9緩存。·

  ··

  每個瀏覽器都有自己的緩存,所以Firefox不會使用由Chrome或IE緩存的文件。

  下面的圖片顯示了一個瀏覽我的電影網站的Fiddler會話。因爲我已經好幾天沒有瀏覽電影網站了,IE9被迫驗證了modernizr和customerjQuery文件。

  

  在Fiddler中選擇緩存選項卡,其中給出了爲什麼需要驗證的詳細信息,以及在不需要服務器驗證的情況下,瀏覽器將在多長時間內可以直接只用這些文件。在下面的示例中,在接下來的2天19小時20分鐘內,IE9將直接從緩存中提取資源,而無需讓服務器檢查(並保存HTTP 304的往返信息)。當響應到期時,Fiddler中的緩存檢查器將根據響應的頭顯示。例如,這裏是IIS 7.5的默認響應,它包含一個ETAG和最後修改的頭,但是沒用過期信息:

  

  沒有提供顯示的HTTP過期信息,這是一個很好的提示,說明你需要做什麼,顯示設置過期時間。最佳實踐建議web開發人員應該爲其內容指定一個明確的過期時間,以確保瀏覽器能夠在不產生HTTP請求條件的情況下重用內容,以重新驗證服務器的內容。如果資源更改,則更改資源的名稱。下面的Web.config文件,添加了內容和腳本文件夾到瀏覽器緩存。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
             <clientCache cacheControlMode="UseExpires" 
                          httpExpires="Mon, 06 May 2013 00:00:00 GMT" />
        </staticContent>
    </system.webServer>
</configuration>

  這裏把過期頭設置爲兩年,在IE9使用F12開發者工具,清楚緩存,然後瀏覽電影網站。使用Fiddler,我們可以看到過期頭,將允許IE9直接從緩存中獲取文件,而不需要在接下來的兩年裏檢查服務器。

  

   用Fiddler和IE9 F12開發者工具監視瀏覽器請求。

  1,打開IE9,點擊F12打開發者工具,之後刪除緩存

  

  2,打開Fiddler

  3,在IE9開發者工具中,選擇Network選項卡,接着選擇開始捕捉(Start capturing),在電影應用程序中選擇Home或About。

  

  Fiddler明確的顯示了IE沒有對靜態資源進行條件請求,也就是說,沒有HTTP GET請求,也沒有來自服務器的HTTP 304響應。爲什麼IE9顯示了GET請求和服務器返回了304的請求?Eric Lawrence在他使用Fiddler進行了13分鐘的調試的演示中解釋了爲什麼。在安裝F12網絡監聽器時,要確定給定的“來自緩存”的響應是否爲“PreNetIO”(例如在本地緩存中是最新的)或“PostNetIO”(例如在本地緩存中,但使用條件HTTP請求用於驗證新鮮(freshness)程度),這是很困難的。因此,有時F12將顯示出誤導的“(304)”當它意味着是(緩存)”時。

  Firebug實際上更糟,它顯示了每個靜態資源的HTTP 200結果。

  

  Chrome開發工具正確的顯示了來自緩存的每個資源。

  

  在ASP.NET MVC項目中加載資源的簡單助手

  下面的代碼顯示了我的修改後的MVC電影項目中的佈局文件,它使用了LoadRes helper來加載靜態資源和CDN資源。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>

    @LoadRes("Site.css")

    @LoadRes("http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.11/themes/redmond/jquery-ui.css")
    @LoadRes("modernizr-1.7.min.js")
    @LoadRes("http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.5.1.min.js")
    @LoadRes("http://ajax.aspnetcdn.com/ajax/jquery.validate/1.5.5/jquery.validate.min.js")
    @LoadRes("http://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.min.js")
    @LoadRes("jquery-ui-1.8.11.custom.min.js")
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>MovieLT</h1>
            </div>
            <div id="logindisplay">
                No Login
            </div>
            <nav>
                <ul id="menu">
                    <li>@Html.ActionLink("Home", "Index", "Movies")</li>
                    <li>@Html.ActionLink("About", "SearchIndex", "Movies")</li>
                </ul>
            </nav>
        </header>
        <section id="main">
            @RenderBody()
        </section>
        <footer>
        </footer>
    </div>
</body>
</html>

@helper LoadRes(string sFile) {    
    
    // Not CDN but JavaScript
    if (!sFile.Contains("http://") && sFile.EndsWith(".js")) {        
    <script src="@Url.Content("~/Scripts/" + sFile)" type="text/javascript"></script>
    }

     // CDN and  JavaScript
    else if (sFile.Contains("http://") && sFile.EndsWith(".js")) {        
    <script src="@sFile" type="text/javascript"></script>
    
    }

    // CDN and CSS
     else if (sFile.Contains("http://") && sFile.EndsWith(".css")) {        
    <link href="@sFile" rel="stylesheet" type="text/css" />
    
     // Not CDN but CSS
    } else if (sFile.EndsWith(".css")) {
    <link href="@Url.Content("~/Content/" + sFile)" rel="stylesheet" type="text/css" />
    }
        
}

  我使用LoadRes幫助類來清理用於加載資源的標記。

  

   參考文獻:

  https://blogs.msdn.microsoft.com/rickandy/2011/05/21/using-cdns-and-expires-to-improve-web-site-performance/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章