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
复制代码
}