.NET MVC中HTML&CSS&JS的压缩与混淆加密

对一个网站的速度性能优化方法之一就是对请求数据的压缩,请求安全性提高就是数据的加密。其实ASP.NET MVC 已经对文件压缩有处理,但开发者依然能够根据自己需要对项目进一步优化。 本篇文章就讲下常规的请求资源压缩与加密!

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的生命周期中,过滤处理请求返回数据达到目的,正则表达式可以根据自己情况优化。

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

        /// 
        /// HtmlTextWriter
        /// 
        private HtmlTextWriter tw;

        /// 
        /// StringWriter
        /// 
        private StringWriter sw;

        /// 
        /// StringBuilder
        /// 
        private StringBuilder sb;

        /// 
        /// HttpWriter
        /// 
        private HttpWriter output;

        #endregion

        /// 
        /// 压缩html代码
        /// 
        /// html代码
        /// 
        private static string Compress(string text)
        {
            Regex reg = new Regex(@"\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;
        }

        /// 
        /// 在执行Action的时候,就把需要的Writer存起来
        /// 
        /// 上下文
        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);
        }

        /// 
        /// 在执行完成后,处理得到的HTML,并将他输出到前台
        /// 
        /// 
        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数据就是过滤后的数据,少了空白,回车等符号;

注意:如果发现有注释代码未过滤掉,请检查项目中cshtml源码中用的注释符号为@* *@,不能用注释。@* *@会在项目编译时就过滤掉,其他方式注释则不会!

CSS压缩

css压缩是项目自带功能,规范使用即可:

1、在项目BundleConfig.cs中
bundles.Add(new StyleBundle("~/content/base").Include(
                "~/css/base.css",//项目原css文件。//捆绑压缩多个css到~/content/base
                "~/css/layer.css"));
2、代码引用压缩后的css:

    //在自己合适的位置
    @Styles.Render("~/content/base")


...

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:

    //在自己合适的位置
    @Scripts.Render("~/bundles/script")

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中引入方式不变

    //在自己合适的位置
    @Scripts.Render("~/bundles/script")

总结:以上是常规处理方法,部分地方可以自己找其他方案实现,只要能达到提高性能的效果,都可以尝试下。比如了解些三方构建工具fis3等。

你可能感兴趣的:(.NET MVC中HTML&CSS&JS的压缩与混淆加密)