HttpCombiner也不記得是誰寫的了,功能是把多個js文件或css文件合併到一塊,壓縮一下一塊兒發給客戶端來優化網站。 用法是這樣的: <script type="text/javascript" src="/Part/Handle/HttpCombiner.ashx?t=js&s=a.js,b.js,dialog/c.js,dialog/d.js"></script> 但這樣又不利於找錯,因此在中間又加了一個方法,可隨時控制是如上引用仍是,以下通常引用: <script type="text/javascript" src="/RES/JS/a.js"></script> <script type="text/javascript" src="/RES/JS/b.js"></script> <script type="text/javascript" src="/RES/JS/dialog/c.js"></script> <script type="text/javascript" src="/RES/JS/dialog/d.js"></script> 修改後引用文件時: <%= HttpCombiner.Requires(true,"js","a.js", "b.js", "dialog/c.js", "dialog/d.js")%> 第一個參數來控制合併 。 通常處理程序cs源碼: 複製代碼 using System; using System.Web; using System.Net; using System.IO; using System.IO.Compression; using System.Text; using System.Web.Caching; public class HttpCombiner : IHttpHandler { #region Config private const bool DO_GZIP = true; private readonly static TimeSpan CACHE_DURATION = TimeSpan.FromDays(30); private const string JSPathPre = "~/RES/JS/"; private const string CSSPathPre = "~/RES/CSS/"; private const string CombinerUrl = "/Part/Handle/HttpCombiner.ashx";//些handler路徑 private const string JSAbsPathPre = "/RES/JS/"; private const string CSSAbsPathPre = "/RES/CSS/"; #endregion #region Requires 默認combin public static string Requires(bool combin, string type, params string[] files) { if (combin) { if (type == "js") { return string.Format("<script type=\"text/javascript\" src=\"{0}?t=js&s={1}\"></script>", CombinerUrl, string.Join(",", files)); } else if (type == "css") { return string.Format("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}?t=css&s={1}\" />", CombinerUrl, string.Join(",", files)); } else { return string.Empty; } } else { if (type == "js") { StringBuilder sb = new StringBuilder(); foreach (var file in files) { sb.AppendFormat("<script type=\"text/javascript\" src=\"{0}{1}\"></script>", JSAbsPathPre, file); sb.AppendLine(); } return sb.ToString(); } else if (type == "css") { StringBuilder sb = new StringBuilder(); foreach (var file in files) { sb.AppendFormat("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}{1}\" />", CSSAbsPathPre, file); sb.AppendLine(); } return sb.ToString(); } else { return string.Empty; } } } public static string Requires(string type, params string[] files) { return Requires(true, type, files); } #endregion #region Process public void ProcessRequest(HttpContext context) { HttpRequest request = context.Request; string setName = request["s"] ?? string.Empty; string contentType = request["t"] ?? string.Empty; if (string.IsNullOrEmpty(contentType)) { contentType = "type/javascript"; } else { if (contentType == "js") { contentType = "type/javascript"; } else if (contentType == "css") { contentType = "text/css"; } else { contentType = "text/plain"; } } bool isCompressed = DO_GZIP && CanGZip(context.Request); UTF8Encoding encoding = new UTF8Encoding(false); if (!WriteFromCache(context, setName, isCompressed, contentType)) { System.Collections.Generic.List<string> dependencyFiles = new System.Collections.Generic.List<string>(); using (MemoryStream memoryStream = new MemoryStream(5000)) { using (Stream writer = isCompressed ? (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream) { string[] fileNames = setName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string fileName in fileNames) { byte[] fileBytes = GetFileBytes(contentType, context, fileName.Trim(), encoding, dependencyFiles); writer.Write(fileBytes, 0, fileBytes.Length); } writer.Close(); } byte[] responseBytes = memoryStream.ToArray(); context.Cache.Insert(GetCacheKey(setName, isCompressed), responseBytes, new CacheDependency(dependencyFiles.ToArray()), System.Web.Caching.Cache.NoAbsoluteExpiration, CACHE_DURATION); WriteBytes(responseBytes, context, isCompressed, contentType); } } } private static byte[] GetFileBytes(string contentType, HttpContext context, string virtualPath, Encoding encoding, System.Collections.Generic.List<string> depencesFile) { if (virtualPath.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase)) { using (WebClient client = new WebClient()) { return client.DownloadData(virtualPath); } } else { if (!virtualPath.StartsWith("~/", StringComparison.InvariantCultureIgnoreCase)) { if (contentType == "text/css") { virtualPath = CSSPathPre + virtualPath; } else if (contentType == "type/javascript") { virtualPath = JSPathPre + virtualPath; } } string physicalPath = context.Server.MapPath(virtualPath); depencesFile.Add(physicalPath); byte[] bytes = File.ReadAllBytes(physicalPath); return bytes; } } private static bool WriteFromCache(HttpContext context, string setName,bool isCompressed, string contentType) { byte[] responseBytes = context.Cache[GetCacheKey(setName, isCompressed)] as byte[]; if (null == responseBytes || 0 == responseBytes.Length) return false; WriteBytes(responseBytes, context, isCompressed, contentType); return true; } private static void WriteBytes(byte[] bytes, HttpContext context,bool isCompressed, string contentType) { HttpResponse response = context.Response; response.AppendHeader("Content-Length", bytes.Length.ToString()); response.ContentType = contentType; if (isCompressed) response.AppendHeader("Content-Encoding", "gzip"); context.Response.Cache.SetCacheability(HttpCacheability.Public); context.Response.Cache.SetExpires(DateTime.Now.Add(CACHE_DURATION)); context.Response.Cache.SetMaxAge(CACHE_DURATION); context.Response.Cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); response.OutputStream.Write(bytes, 0, bytes.Length); response.Flush(); } private static bool CanGZip(HttpRequest request) { string acceptEncoding = request.Headers["Accept-Encoding"]; if (!string.IsNullOrEmpty(acceptEncoding) && (acceptEncoding.Contains("gzip") || acceptEncoding.Contains("deflate"))) return true; return false; } private static string GetCacheKey(string setName, bool isCompressed) { return "HttpCombiner." + setName + "." + isCompressed; } public bool IsReusable { get { return true; } } #endregion 複製代碼 }