對一個網站的速度性能優(yōu)化方法之一就是對請求數據的壓縮,請求安全性提高就是數據的加密。其實ASP.NET MVC 已經對文件壓縮有處理,但開發(fā)者依然能夠根據自己需要對項目進一步優(yōu)化。 本篇文章就講下常規(guī)的請求資源壓縮與加密!
HTML壓縮
1.GZIP壓縮
Gzip開啟以后會將輸出到用戶瀏覽器的數據進行壓縮的處理,這樣就會減小通過網絡傳輸的數據量,提高瀏覽的速度。
注意:實際阿里云服務器已經自帶GZIP壓縮,項目無需再處理。

講下沒有服務器沒有功能情況下(雖然不太可能)的項目代碼實現:寫一個ActionFilter來實現GZIP
CompressFilterAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.IO.Compression;
public class CompressFilterAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContextfilterContext)
{
string acceptEncoding = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
if (String.IsNullOrEmpty(acceptEncoding)) return;
var response = filterContext.HttpContext.Response;
acceptEncoding = acceptEncoding.ToUpperInvariant();
if (acceptEncoding.Contains("GZIP"))
{
response.AppendHeader("Content-Encoding", "gzip");
response.Filter = new GZipStream(response.Filter,CompressionMode.Compress);
}
else if (acceptEncoding.Contains("DEFLATE"))
{
response.AppendHeader("Content-Encoding", "deflate");
response.Filter = new DeflateStream(response.Filter,CompressionMode.Compress);
}
}
}
調用:可以在FilterConfig.cs設置全局實現(建議):
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//異常處理
filters.Add(new HandleErrorAttribute());
//GZIP壓縮
filters.Add(new CompressFilterAttribute());
}
}
2.去空白
利用正則匹配字符,在action的生命周期中,過濾處理請求返回數據達到目的,正則表達式可以根據自己情況優(yōu)化。
WhitespaceFilterAttribute.cs
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
namespace lq.Filter
{
public class WhitespaceFilterAttribute : ActionFilterAttribute
{
public bool IsCheck { get; set; } //此屬性為一個bool值,true表示驗證Cookies,false表示不驗證
#region Private
/// <summary>
/// HtmlTextWriter
/// </summary>
private HtmlTextWriter tw;
/// <summary>
/// StringWriter
/// </summary>
private StringWriter sw;
/// <summary>
/// StringBuilder
/// </summary>
private StringBuilder sb;
/// <summary>
/// HttpWriter
/// </summary>
private HttpWriter output;
#endregion
/// <summary>
/// 壓縮html代碼
/// </summary>
/// <param name="text">html代碼</param>
/// <returns></returns>
private static string Compress(string text)
{
Regex reg = new Regex(@"\s*(</?[^\s/>]+[^>]*>)\s+(</?[^\s/>]+[^>]*>)\s*");
text = reg.Replace(text, m => m.Groups[1].Value + m.Groups[2].Value);
reg = new Regex(@"(?<=>)\s|\n|\t(?=<)");
text = reg.Replace(text, string.Empty);
return text;
}
/// <summary>
/// 在執(zhí)行Action的時候,就把需要的Writer存起來
/// </summary>
/// <param name="filterContext">上下文</param>
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (IsCheck)
{
sb = new StringBuilder();
sw = new StringWriter(sb);
tw = new HtmlTextWriter(sw);
output = (HttpWriter) filterContext.RequestContext.HttpContext.Response.Output;
filterContext.RequestContext.HttpContext.Response.Output = tw;
}
base.OnActionExecuting(filterContext);
}
/// <summary>
/// 在執(zhí)行完成后,處理得到的HTML,并將他輸出到前臺
/// </summary>
/// <param name="filterContext"></param>
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (IsCheck)
{
string response = Compress(sb.ToString());
if (!string.IsNullOrWhiteSpace(response))
{
output.Write(response);
}
else
{
filterContext.RequestContext.HttpContext.Response.Output = output;
}
}
}
}
}
調用:可以在FilterConfig.cs設置全局實現(建議):
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//異常處理
filters.Add(new HandleErrorAttribute());
//html過濾空格壓縮
filters.Add(new WhitespaceFilterAttribute(){ IsCheck=true });
}
}
如果部分Controller的Action不需要調用該功能,可單獨在action上使用[WhitespaceFilter(IsCheck = false)]false屏蔽該功能:
[WhitespaceFilter(IsCheck = false)]//false屏蔽
public ActionResult Error(int statusCode, Exception exception)
{
Response.StatusCode = statusCode;
ViewBag.StatusCode = statusCode;
var vModel = new BaseViewModel();
vModel.Title = "頁面未找到";
return View(vModel);
}
這樣請求的html數據就是過濾后的數據,少了空白,回車等符號;
注意:如果發(fā)現有注釋代碼未過濾掉,請檢查項目中cshtml源碼中用的注釋符號為@* *@,不能用<!-- -->注釋。@* *@會在項目編譯時就過濾掉,其他方式注釋則不會!
CSS壓縮
css壓縮是項目自帶功能,規(guī)范使用即可:
1、在項目BundleConfig.cs中
bundles.Add(new StyleBundle("~/content/base").Include(
"~/css/base.css",//項目原css文件。//捆綁壓縮多個css到~/content/base
"~/css/layer.css"));
2、代碼引用壓縮后的css:
<head>
//在自己合適的位置
@Styles.Render("~/content/base")
</head>
<body>
...
</body>
JavaScript壓縮與混淆加密
1.壓縮
自帶壓縮功能與css壓縮一樣:
1、在項目BundleConfig.cs中
bundles.Add(new ScriptBundle("~/bundles/script").Include(
"~/Scripts/lq/helper.js",
"~/Scripts/lq/base.js",
"~/Scripts/lq/popup.js",
"~/Scripts/lq/cookie.js"));
2、在cshtml中引入壓縮后的js:
<body>
//在自己合適的位置
@Scripts.Render("~/bundles/script")
</body>
2.混淆加密
使用packer2加密,點擊下載packer2.net.zip。
用到的相關源碼文件有:ECMAScriptPacker.cs & ParseMaster.cs, 將文件導入項目中合適的目錄下例如新建目錄:ScriptBundle,然后再在該目下新建調用實現類并調用:
1、新建一個類CustomJsMinify實現IBundleTransform接口并實現方法Process
需要處理的javascript的源碼就在Process方法中,在這里我們就可以對javascript源碼進行壓縮,混淆加密:
using System;
using System.Web.Optimization;
namespace lq.ScriptBundle
{
public class CustomJsMinify : IBundleTransform
{
public void Process(BundleContext context, BundleResponse response)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (response == null)
{
throw new ArgumentNullException("response");
}
if (!context.EnableInstrumentation)
{
try
{
//最后一個參數為false,防止生成混淆代碼時候特殊因特殊詞出錯
ECMAScriptPacker p = new ECMAScriptPacker(ECMAScriptPacker.PackerEncoding.Normal, true, false);
response.Content = p.Pack(response.Content);
}
catch (Exception ex)
{
response.Content = "/*\r\nError:" + ex.Message + "\r\n*/\r\n" + response.Content;
}
}
response.ContentType = "text/javascript";
}
}
}
//最后一個參數為false,防止生成混淆代碼時候特殊因特殊詞出錯:
ECMAScriptPacker p = new ECMAScriptPacker(ECMAScriptPacker.PackerEncoding.Normal, true, false);
2、新建一個類CustomScriptBundle繼承Bundle
using System.Web.Optimization;
namespace lq.ScriptBundle
{
public class CustomScriptBundle : Bundle
{
public CustomScriptBundle(string virtualPath) : this(virtualPath, null)
{
}
public CustomScriptBundle(string virtualPath, string cdnPath) : base(virtualPath, cdnPath, new IBundleTransform[]
{
new CustomJsMinify()
})
{
base.ConcatenationToken = ";";
}
}
}
3、在BundleConfig中配置JavaScript時用CustomScriptBundle
bundles.Add(new CustomScriptBundle("~/bundles/script").Include(
"~/Scripts/lq/helper.js",
"~/Scripts/lq/base.js",
"~/Scripts/lq/popup.js",
"~/Scripts/lq/cookie.js"));
4、在cshtml中引入方式不變
<body>
//在自己合適的位置
@Scripts.Render("~/bundles/script")
</body>
總結:以上是常規(guī)處理方法,部分地方可以自己找其他方案實現,只要能達到提高性能的效果,都可以嘗試下。比如了解些三方構建工具fis3等。