熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

ASP.NET AJAX 資源腳本壓縮的秘密

2013-11-13 10:25:12  來源: .NET編程 
   從ATLAS到正式的ASPNET AJAX已經發生了根本性的變化了所以當時的情況就不再多做介紹了還是先來看看一組數據  Resource Name DEBUG Uncompressed DEBUG  Compressed  Release Uncompressed Release Compressed MicrosoftAjaxjs bytes bytes bytes bytes MicrosoftAjaxWebFormsjs bytes bytes bytes bytes

  上表的數據我就不再多說了一目了然那麼由誰來決定是使用Debug版本還是Release版本你可以設置ScriptManager的ScriptMode屬性也可以修改nfig的compilation節點的deubg屬性

  現在我們再來討論一下該如何實現腳本的壓縮的?其實這個也是相當簡單的從ASPNET AJAX給我們提供的默認配合節點中可以非常明顯的看到這樣一段代碼

   <scriptResourceHandler enableCompression=true enableCaching=true /> 


 但是它是被注釋著的我們只需要把這個注釋去掉就OK了奇跡就這樣發生了

  但是事實完全就是這樣嗎?未必!我想說的是這裡的壓縮並不適用於低於IE的浏覽器包括IE有人肯定不信了IE可是絕大多數據普通用戶使用的浏覽器這個都不支持那這個功能還有什麼意義啊!您還真別不信事實就是這樣我們先來看一段代碼然後再來看一個例子

  直接找到RuntimeScriptResourceHandler類它實現了IScriptResourceHandler 該接口只有一個方法GetScriptResourceUrl顧名思義它就是獲取訪問腳本資源的URL地址在RuntimeScriptResourceHandler中它的實現是這樣的:

   string IScriptResourceHandlerGetScriptResourceUrl(Assembly assembly string resourceName CultureInfo culture bool zip bool notifyScriptLoaded)
{
 if (!ScriptResourceHandlerIsCompressionEnabled(HttpContextCurrent))
{
 zip = false;
}
 Tuple tuple = new Tuple(new object[]
{
 assembly resourceName culture zip notifyScriptLoaded
}
);
 string text = (string) _urlCache[tuple];
 if (text == null)
{
 string name;
 ScriptResourceHandlerScriptResourceInfo instance = ScriptResourceHandlerScriptResourceInfoGetInstance(assembly resourceName);
 if (instance == ScriptResourceHandlerScriptResourceInfoEmpty)
 {
  ThrowUnknownResource(resourceName);
 }
 Stream manifestResourceStream = assemblyGetManifestResourceStream(instanceScriptName);
  if ((manifestResourceStream == null) || (manifestResourceStreamReadByte() == ))
  {
   ThrowUnknownResource(resourceName);
  }
 culture = ScriptResourceHandlerDetermineNearestAvailableCulture(assembly resourceName culture);
 Pair<AssemblyName DateTime> assemblyInfo = ScriptResourceHandlerGetAssemblyInfo(assembly);
 AssemblyName first = assemblyInfoFirst;
 DateTime second = assemblyInfoSecond;
 if (assemblyGlobalAssemblyCache)
 {
  StringBuilder builder = new StringBuilder();
  builderAppend(firstName);
  builderAppend();
  builderAppend(firstVersion);
  builderAppend();
  if (firstCultureInfo != null)
  {
   builderAppend(firstCultureInfo);
  }
 builderAppend();
 builderAppend(HexParserToString(firstGetPublicKeyToken()));
 name = builderToString();
 }
else
 {
 name = firstName;
 }
 if (_absoluteScriptResourceUrl == null)
 {
  _absoluteScriptResourceUrl = VirtualPathUtilityToAbsolute(~/ScriptResourceaxd);
 }
 text = stringConcat(new object[]
{
_absoluteScriptResourceUrl ?d= ScriptResourceHandlerEncryptString((zip ? (notifyScriptLoaded ? Z : z) : (notifyScriptLoaded ? U : u)) + name + | + resourceName + | + cultureToString()) &t= secondTicks
}
);
 _urlCache[tuple] = text;
}
 return text;
}
code

  其中zip參數是用於指定是否生成帶有壓縮版本的URL地址如果zip為true則返回的參數d的第一個字符為Z或z否則為U或u具體是如何去壓縮的我們現在先不管反正URL地址中的地址欄參數d的第一字符為Z或z就表明訪問的資源被請求到客戶端前會被壓縮因此要訪問壓縮的腳本資源就要保證zip參數為true那這個參數從何而來呢?它是由ScriptManager的Zip屬性原原本本的被傳遞到這個方法中這在傳遞的過程當中沒有被修改過而ScriptManager的Zip的屬性定義如下


   internal bool Zip{
get
{
if (!this_zipSet)
{
this_zip = HeaderUtilityIsEncodingInAcceptList(thisIPageRequestHeaders[Acceptencoding] gzip);
this_zipSet = true;
}
return this_zip;
}
}
code

  決定它值的是客戶端HTTP請求頭部是否帶有AcceptEncoding: gzip因此大部分的浏覽器都支持GZIP壓縮過的HTTP輸出流程因此大部份浏覽器的請求頭部都會有這麼一段AcceptEncoding: gzip deflate因此這個值在接受IE請求時應該是為true才對的而它得到的應該也是個壓縮版本的資源URL請求才對啊?除非CODE中的zip參數被改為false了再回過頭來看CODE的開始部分有這麼一段代碼:

   if (!ScriptResourceHandlerIsCompressionEnabled(HttpContextCurrent))
{
zip = false;
}
code 

  只有在這裡zip的值才有可能被修改為false那我們再來看看ScriptResourceHandlerIsCompressionEnabled究竟做了此什麼了?

   private static bool IsCompressionEnabled(HttpContext context)
{
if (!ScriptingScriptResourceHandlerSectionApplicationSettingsEnableCompression)
{
return false;
}
if ((context != null) && contextRequestBrowserIsBrowser(IE))
{
return (contextRequestBrowserMajorVersion > );
}
return true;
}
code

  第一我們可以確定EnableCompression的值為true第二我們使用的是IE會執行return (contextRequestBrowserMajorVersion > ) 因為我們使用的IE這邊就會返回false回到CODE zip的值就會被修改成false了而此時就會返回不被壓縮的URL地址了問題就在這裡可這是為什麼呢?我想一般情況下我們肯定會不理解的看了這個你就清楚了x?familyid=bbabbaecaaf&displaylang=en 原來在IE的SP版本中接收GZIP的數據會有問題而這邊就是給了解決這個問題的補丁包ASPNET AJAX團隊可能擔心由於這個問題引起的部分IE浏覽器無法正常使用ASPNET ajax保險起見在IE的請求中永不使用壓縮腳本

  分析了代碼為了讓我們有更直觀的印象再來看一段代碼例子

   protected void Page_Load(object sender EventArgs e)
{
NameValueCollection queryString = HttpUtilityParseQueryString(GetScriptResourceUrl());
ResponseWrite(DecryptString(queryString[]));
}
private static string DecryptString(string s)
{
MethodInfo _decryptString = typeof(Page)GetMethod(DecryptString BindingFlagsNonPublic | BindingFlagsStatic);
return (string)_decryptStringInvoke(null new object[] { s });
}
private string GetScriptResourceUrl()
{
MethodInfo GetScriptResourceUrl = typeof(ScriptManager)GetMethod(GetScriptResourceUrl BindingFlagsNonPublic | BindingFlagsInstance);
 return (string)GetScriptResourceUrlInvoke(sm new object[]
{
MicrosoftAjaxjs smGetType()Assembly
}
);
}

  在IE它輸出的是 USystemWebExtensions|MicrosoftAjaxjs| 而在FF中它輸出的是ZSystemWebExtensions|MicrosoftAjaxjs|

  這兩個不同的輸出值完全就可以體現了它們請求行為的不同

  接下來簡單討論一下我們如何修改讓它去掉這個限制在ScriptResourceHandler有一個這樣的靜態方法SetScriptResourceHandler我們可以重新實現一個IScriptResourceHandler類用這個法植入到ASPNET AJAX內部讓它們使用但問題是SetScriptResourceHandler是一個internal的方法使用反射呗那還能怎麼樣誰讓它這樣設計既提供這個方法又不想讓人用!

  OK對這個問題的研究就先到這邊了


From:http://tw.wingwit.com/Article/program/net/201311/13561.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.