久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

站點靜態(tài)資源優(yōu)化合并解決方案

 CevenCheng 2011-07-15

站點靜態(tài)資源優(yōu)化合并解決方案

背景

 

站點經過幾年的積累,一個頁面上需要加載數(shù)十個腳本和樣式文件(之后我們把腳本和樣式統(tǒng)稱為靜態(tài)資源),,在瀏覽器沒有緩存的情況下如此之多的請求數(shù)不但會對服務器有比較大的壓力(這個問題可以通過CDN或反向代理解決),,而且頁面呈現(xiàn)也會非常慢(我們知道腳本的下載會阻塞其它資源下載以及頁面呈現(xiàn))。由于一個站點往往頁面數(shù)量很多,,而且由于靜態(tài)資源分布于頁面/用戶控件以及面板頁等各種類型的頁面,,所以人工逐個頁面修改合并耗時比較多。而且這些資源都是沒有經過精簡,,包含大量注釋和空格空行,,我們還需要進行資源的壓縮?;谶@些原因,,提出需求能否有一個自動化的框架來自動處理這些靜態(tài)資源。調查了現(xiàn)有的一些框架,很多框架功能完善,,但是有兩個主要缺點:

1) 需要人工配置合并哪些資源為一個資源包,,不能實現(xiàn)自動化的把每一個頁面的腳本和樣式分別合并為一個文件。

2) 需要大量的代碼改動,,刪除現(xiàn)有的樣式和腳本聲明然后進控件的聲明或配置文件的配置,,很難通過工具自動替換相關的客戶端標簽。

因此,,我們只有自己來制作一個具有4C功能的資源合并框架,,實現(xiàn)合并(Combine)/Compress(壓縮)/Compact(精簡)和Cache(緩存)。

 

介紹

 

ResourceMerge框架有下列功能和特性:

1) 和其它框架不同,,不需要把靜態(tài)資源的聲明歸并到一處(比如一個ScriptManager來聲明所有腳本),,只需要原地替換。

1) 服務器控件的作用只是收集這些靜態(tài)資源的信息,,然后通過HttpModule在合適的時候把合并后的標簽渲染到頁面合適位置,,比如腳本放在Form的底部,樣式放在Head中或Form的頭部,。

2) 可以通過配置選擇為某些頁面或所有頁面進行靜態(tài)資源的合并/精簡/Gzip壓縮/瀏覽器緩存等等。

3) 所有的配置改動都不需要重啟網站,,在下一個請求到達之后新的配置生效。

在這里要補充說明幾點:

1) 任何事情都是有利有弊的,,我們知道如果靜態(tài)資源數(shù)量很多(甚至重復)會增加請求數(shù),增加頁面打開時間,,但是如果盲目合并為一個很可能會增加流量,,假設有資源A/B/C,頁面1和頁面2分別用刀了AB和ABC,,如果一個頁面的資源合并為一個文件的話,頁面1下載了AB,,頁面2下載了ABC,,導致AB資源的流量重復下載了,在這種情況下最佳的做法是把AB合并為一個文件,。我們的項目有特殊性,,經過幾年的積累,開發(fā)人員并不清楚需要怎么去合并,,我們只能實現(xiàn)這種自動化的合并,。

2) 本來我們的資源都是本地資源,這有兩個壞處,,一是不能通過CDN給Web服務器釋放靜態(tài)資源這塊的訪問壓力,,二是在請求靜態(tài)資源的時候不必要的一些Cookie瀏覽器也會發(fā)動給服務器。之后我們進行了靜態(tài)資源分離的項目,,把所有靜態(tài)資源分離到了cdn域名,。其實對于我們靜態(tài)資源合并來說這樣的分離反而不是一件好事情,,因為我們的Web服務器在讀取靜態(tài)資源的時候,,如果是本地的文件會很快,,如果是一個網絡地址,那么讀取會比較慢而且還有可能在網絡不穩(wěn)定的情況下出現(xiàn)讀取不完整的情況,,因此最好是在Web服務器上設置一些Host,把原先cdn域名的直接解析到我們靜態(tài)資源服務器的內網IP地址上。

下面介紹一下基本的流程:

image

我們可以看到由于很多需要合并的文件來自于網絡,,我們的緩存情況變得復雜了點,,如果一個來自于網絡的文件更新了之后合并后的文件并沒有改動可能因為以下幾個原因:

1) Web服務器訪問到的合并前的文件被CDN或反向代理緩存,我們只有等待緩存過期。

2) 合并后的文件服務端緩存沒到期,,我們可以通過MergeHandler.ashx?action=clear來清空緩存,。

3) 合并后的文件又被前端的反向代理或CDN緩存,我們只有等待緩存過期,。

4) 合并后的文件瀏覽器緩存沒有到期,,瀏覽器沒有發(fā)出請求,我們可以清空瀏覽器緩存,。

 

框架解析

 

ConfigProvider.cs 實現(xiàn)了把xml中的配置讀取到實體中,,并且實現(xiàn)文件依賴,一旦文件有改動,,立即把過期開關打開,,通知下一個請求來更新配置。

ConfigSet.cs 對應配置的實體,,我們可以為全局應用一套配置,,也可以為單獨的頁面應用一套配置。

CssMinifier.cs 精簡樣式文件,。

JsMinifier.cs 精簡腳本文件,。

MergedResource.cs 內存中保存的有關和合并后的資源信息的實體。

RawResource.cs 服務器控件,,聲明靜態(tài)資源的地址,,是否合并等開關,,這個控件并不會渲染合并后資源的標簽,,唯一作用只是在Init的時候收集聲明信息并且寫入內存。

MergeModule.cs 在頁面Init的時候把合并后的標簽寫到頁面合適的位置(如果能找到Page的Header的話就把樣式寫入Header否則加到Form的第一個控件),,由于我們是在這里添加控件,,因此需要保證頁面上不能有類似<%=%>這樣的代碼,,必須替換為<%#%>綁定。

MergeHandler.cs 這個Handler就是用來根據(jù)ID從內存中獲取原始文件列表,,然后進行合并/精簡/壓縮處理,,并且把處理后的文件緩存到memcached中,最后打上瀏覽器緩存的頭以合適的ContentType進行輸出,。同時這個Handler也提供了action=info和action=clear兩個開關來查看合并后的文件列表(什么時候過期,,保存在哪里)以及清空緩存這兩個小功能。

MergeService.cs 提供了一些合并的主要功能,,同時也會在這里處理樣式文件中的@import(提到第一行)和@charset(刪除),。

ResourceCache.cs 處理所有和緩存相關的功能。

UrlVariable.cs 支持在Url中使用$$appSettings.jspath$$的方式來引用AppSettings中的Value:<add key="jspath" value="images."/>,。

 

配置

 

0) 引用ResourceMerge.Core.dll,。

1) 配置web.config文件:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="ResourceMergeConfigFilePath" value="~/Config/ResourceMerge.config"/>
    <add key="jspath" value="images."/>
  </appSettings>
  <connectionStrings/>
  <system.web>
    <pages>
      <controls>
        <add assembly="ResourceMerge.Core" tagPrefix="ResourceMerge" namespace="ResourceMerge.Core"/>
      </controls>
    </pages>
    <compilation debug="true">
    </compilation>
    <authentication mode="Windows"/>
    <httpModules>
      <add name="ResourceMerge.Core.MergeModule" type="ResourceMerge.Core.MergeModule, ResourceMerge.Core"/>
    </httpModules>
    <httpHandlers>
      <add path="MergeHandler.ashx" type="ResourceMerge.Core.MergeHandler, ResourceMerge.Core" verb="GET,HEAD" />     
    </httpHandlers>
  </system.web>
</configuration>

主要是配置Handler/Module,,還有就是RawResource控件的配置,在appSettings中需要配置配置文件的地址,,默認就是這個地址,。

2) 配置配置文件,所有的配置都具有默認值,,但是配置文件一定要存在,,注意必須修改CacheKeyPrefix的值。

<?xml version="1.0" encoding="utf-8" ?>
<ResourceMerge>
  <Common>
    <!--輸出合并后文件Handler地址,,可以是一個相對路徑也可以是絕對路徑,,默認為~/MergeHandler.ashx-->
    <MergeHandlerUrl>~/MergeHandler.ashx</MergeHandlerUrl>
    <!--服務端緩存鍵前綴,修改這個值能立即讓服務端緩存失效,,默認為ResourceMerge_,,每一個網站必須設定不同的值,否則會看到其它網站的緩存或清空其它網站的緩存-->
    <CacheKeyPrefix>TestResourceMerge_</CacheKeyPrefix>
    <!--全局應用的ConfigSetName,,默認為名為Default的配置,,都是默認值-->
    <GlobalConfigSetName>s1</GlobalConfigSetName>
  </Common>
  <ConfigSets>
    <ConfigSet>
      <!--標識名-->
      <Name>s1</Name>
      <!--資源的字符集,需要和實際文件字符集對應否則可能出現(xiàn)亂碼,,默認為utf-8-->
      <Charset>utf-8</Charset>
      <!--是否進行樣式文件合并,,即使不合并也會重新調整資源的呈現(xiàn)位置,默認為true-->
      <IsMergeStyle>true</IsMergeStyle>  
      <!--是否進行樣式文件最小化,,比如去除空行和注釋等,,默認為true-->
      <IsMinifyStyle>true</IsMinifyStyle>
      <!--是否進行腳本文件合并,即使不合并也會重新調整資源的呈現(xiàn)位置,,默認為true-->
      <IsMergeScript>true</IsMergeScript>
      <!--是否進行腳本文件最小化,,比如去除空行和注釋等,默認為true-->
      <IsMinifyScript>true</IsMinifyScript>
      <!--是否進行文件gzip壓縮,,如果web服務器或cdn已經開啟了壓縮,,這里就不需要開了,默認為true-->
      <IsCompress>false</IsCompress>
      <!--是否從遠程獲取資源的時候支持gzip或deflate,,默認為true-->
      <GetCompressedRemoteResource>false</GetCompressedRemoteResource>
      <!--是否把合并以及壓縮后的文件保存在服務端內存中,,默認為true-->
      <UseServerCache>true</UseServerCache>
      <!--是否為合并以及壓縮后的文件開啟客戶端瀏覽器緩存,,默認為true-->
      <UseClientCache>false</UseClientCache>
      <!--服務端緩存過期時間,,單位是秒,默認為3600-->
      <ServerCacheDuration>30</ServerCacheDuration>
      <!--客戶端緩存過期時間,,單位是秒,,默認為3600-->
      <ClientCacheDuration>60</ClientCacheDuration>
    </ConfigSet>
  </ConfigSets>
  <Pages>
    <Page Url="~/WebForm1.aspx" ConfigSetName="s2" />
  </Pages>
</ResourceMerge>

每一個配置項這里已經說明了,各個站點需要根據(jù)自己的需要來設置合適的緩存時間,。

3) 由于合并后的文件并沒有保存在文件中而是保存在memcached中,,所以還需要配置memcached:

<?xml version="1.0" encoding="utf-8" ?>
<memcached-configuration xmlns="urn:memcached-configuration">
  <master>
    <memcached>
      <server address="192.168.135.11" port="11211" />
      <socket-pool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
    </memcached>
  </master>
</memcached-configuration>

4) 相關代碼修改:

protected void Application_Start(object sender, EventArgs e)
{
    MergeService.Start(); 
}

protected void Application_End(object sender, EventArgs e)
{
    MergeService.Stop();
}

Global里面需要添加相關代碼,,最主要的是把所有用戶控件/頁面/母板頁中聲明腳本和樣式的客戶端tag修改為服務端tag(可以通過補充中提到的工具自動進行):

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site1.master.cs" Inherits="ResourceMerge.DemoWebApp.Site1" %>

<%@ Register Assembly="ResourceMerge.Core" Namespace="ResourceMerge.Core" TagPrefix="cc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www./1999/xhtml">
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
  <script type="text/javascript" language="javascript" src="http://<%# System.Configuration.ConfigurationManager.AppSettings["jspath"].ToString() %>/PagesScript/www/DefaultNewV1.js" charset="gb2312" ></script>
        <ResourceMerge:RawResource ID="RawResource1" runat="server" Url="http://images./5173/css/base.css" />
        <ResourceMerge:RawResource ID="RawResource2" runat="server" Url="~/RESOURCE/StylesheetSample2.css" />
        <ResourceMerge:RawResource ID="RawResource4" runat="server" Url="~/RESOURCE/StylesheetSample3.css" />
        <ResourceMerge:RawResource ID="RawResource3" runat="server" Url="~/RESOURCE/SampleJavaSCRIPT.js"/>

        <ResourceMerge:RawResource ID="RawResource5" runat="server" Url="http://$$appSettings.jspath$$/5173/js/layer/layer31.js" />
        <ResourceMerge:RawResource ID="RawResource6" runat="server" Url="http://$$appSettings.jspath$$/js/common/floater/v1.js" />
        <ResourceMerge:RawResource ID="RawResource7" runat="server" Url="http://images./JS/JScript/PagesScript/www/consummateinfo.js"
            Charset="gb2312" />
        <ResourceMerge:RawResource ID="RawResource8" runat="server" Url="http://images./5173/js/newIndex/new_index.js" />
        <ResourceMerge:RawResource ID="RawResource10" runat="server" Url="http://images./5173/js/newIndex/toolTip.js" />
        <ResourceMerge:RawResource ID="RawResource12" runat="server" ResourceType="Style">
            .tradbutton { BORDER-RIGHT: #ff9900 0px solid; PADDING-RIGHT: 0px; BORDER-TOP: #ff9900
            0px solid; PADDING-LEFT: 0px; FONT-SIZE: 12px; BACKGROUND-IMAGE: url(http://images.5173CDN.com/Images/list_20070123.gif);
            PADDING-BOTTOM: 0px; MARGIN: 0px; BORDER-LEFT: #ff9900 0px solid; WIDTH: 62px; COLOR:
            #ff7800; PADDING-TOP: 2px; BORDER-BOTTOM: #ff9900 0px solid; HEIGHT: 20px; BACKGROUND-COLOR:
            #fff }
        </ResourceMerge:RawResource>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
        
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    </div>
    </form>
</body>
</html>

可以看到,即使是內聯(lián)的樣式或腳本也可以包裹在服務器控件之內,,當然,,這個時候我們就不要聲明Url屬性了。我們也可以編程方式添加資源:

protected override void OnPreInit(EventArgs e)
{
     for (int i = 1; i <= 3; i++)
    {
        ResourceMerge.Core.MergeService.AddResouece("~/RESOURCE/Script0" + i + ".js");
    }
    for (int i = 1; i <= 3; i++)
    {
        ResourceMerge.Core.MergeService.AddResouece("~/RESOURCE/Style0" + i + ".css");
    }

    ResourceMerge.Core.MergeService.AddResource(new ResourceMerge.Core.ResourceItem
    {
        ResourceType = ResourceMerge.Core.ResourceType.Style,
        Url = "~/RESOURCE/style.css",
    });
    base.OnPreInit(e);
}

這里要說明幾點:

1) 如果路徑中需要用到web.config中appsettings中的內容,,可以這么寫:

<ResourceMerge:RawResource ID="RawResource5" runat="server" Url="http://$$appSettings.jspath$$/5173/js/layer/layer31.js" />
<ResourceMerge:RawResource ID="RawResource6" runat="server" Url="http://$$appSettings.jspath$$/js/common/floater/v1.js" />

2) 頁面中所有<%=%>必須替換為<%#%>,,但是不需要在后臺代碼中寫DataBind()。

3) 需要保留樣式或腳本文件的charset聲明,,服務器控件其它屬性如下:

public string Url { get; set; }

public bool? IsMinify { get; set; }

public bool? IsMerge { get; set; }

public ResourceType ResourceType { get; set; }

public string Charset { get; set; }

public string Content { get; set; }

public int RenderPriority { get; set; }

public RenderLocation RenderLocation { get; set; }

在配置文件中我們定義的是整個站點或某個頁面的配置,,在服務器控件中可以配置某個資源的Url,是否需要精簡,,是否需要合并,,資源的類型(默認是Auto枚舉,自動根據(jù)擴展名判斷),,字符集(默認是配置文件中配置的字符集),,以及呈現(xiàn)的次序(數(shù)字越小越靠前)和呈現(xiàn)的位置:

public enum RenderLocation
{
    Auto = 0,
    Head = 1,
    FormTop = 2,
    FormButtom = 3,
}

(如果開啟合并的話呈現(xiàn)位置配置無效)

這樣就完成了所有的配置

 

補充說明

 

1) 如果使用服務端緩存的話,可以通過MergeHandler.ashx?action=info地址來查看緩存列表

image 

 

2) 我們知道,,如果樣式表中有@import,,那么需要放在開始,因此合并后的樣式中的所有@import會提到最前面,,并且原先的地方會注釋:

image 

并且我們可以觀察頂部的毫秒數(shù)來判斷這個文件是新生成的還是從緩存中獲取的,。

 

3) 可以使用提供的工具來一次性替換整個網站的客戶端tag為服務端tag,也就是解決方案中的UIOA項目:

image 

選擇路徑后點擊批量合成可以把整個站點下所有aspx/ascx/master文件中的客戶端link/script/stype的tag替換為服務端tag,,把<%=%>替換為<%#%>,。

 

需要特別注意,工具只是機械性替換所有聲明,,我們需要手動對下列情況進行處理:

a) 對于有些框架性的文件,,比如jquery,不需要合并(這個工具已經會自動判斷了),。

b) 由于合并后的腳本在尾部聲明,,所以頁面中穿插的內聯(lián)腳本如果引用到某些函數(shù)的話會出錯,那么這些腳本就不能合并,,比如廣告,。

c) 一定要注意在替換標簽的時候設置正確的charset,否則很可能出現(xiàn)亂碼,,如果合并的靜態(tài)資源本身是動態(tài)生成的并沒有擴展名,,那么我們需要設置ResourceType枚舉。

d) 如果有一些腳本包含動態(tài)內容,,或者是不允許所有用戶共用一份的話就不適合合并,。

 

4) 由于很多腳本和樣式都有錯誤,,所以我們并沒有使用yui mini,ajax mini等框架來最小化腳本和樣式,,只是用了最簡單的算法刪除了空行注釋等內容,。

 

常見錯誤

 

1) 樣式丟失: 檢查樣式文件是否合并了,檢查樣式是否是通過@import引入的,,框架是否把@import提到了最前面,。

2) 腳本錯誤: 一般來說腳本錯誤大多數(shù)是由于部分腳本合并了,部分腳本沒合并引起的,。由于沒合并的腳本調用了合并后的腳本文件中的函數(shù),,而合并后的文件比較大尚未下載完成,這個時候會發(fā)生錯誤,。一般解決方法是把那個腳本設置為IsMerge=false不合并,,或索性把外部的調用這個腳本的函數(shù)也進行合并,或就是通過setTimeout延遲這個腳本的執(zhí)行,。大多數(shù)的腳本錯誤都是因此次序問題而產生的,,默認情況下合并后的腳本在Form的尾部輸出,頁面中如果有其它地方調用了其中的函數(shù)那么就會出錯,。

3) 偶爾產生上述錯誤: 我們知道,,合并腳本的工作是Web服務器進行的,如果某個時刻網絡不好,,Web服務器正從網絡上讀取原始的靜態(tài)資源,,那么很可能產生下載不全的情況,然后Web服務器會設置一定時間的緩存,,那么在這段時間內都會出現(xiàn)錯誤,。這個時候可以讓監(jiān)控相關人員通過MergaHandler.ashx?action=clear來清空緩存重新生成即可。

 

所有代碼在這里下載(包括框架/測試網站以及替換工具),。

作者:lovecindywang
本文版權歸作者和博客園共有,,歡迎轉載,但未經作者同意必須保留此段聲明,,且在文章頁面明顯位置給出原文連接,,否則保留追究法律責任的權利。

    本站是提供個人知識管理的網絡存儲空間,,所有內容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多