.NET MVC中HTML&CSS&JS的壓縮與混淆加密

對一個網站的速度性能優(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等。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容