美文网首页
.NET MVC中HTML&CSS&JS的压缩与

.NET MVC中HTML&CSS&JS的压缩与

作者: BugChester | 来源:发表于2018-08-06 14:39 被阅读297次

    对一个网站的速度性能优化方法之一就是对请求数据的压缩,请求安全性提高就是数据的加密。其实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
    
            /// <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>
            /// 在执行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>
            /// 在执行完成后,处理得到的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数据就是过滤后的数据,少了空白,回车等符号;

    注意:如果发现有注释代码未过滤掉,请检查项目中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:
    <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>
    

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

    相关文章

      网友评论

          本文标题:.NET MVC中HTML&CSS&JS的压缩与

          本文链接:https://www.haomeiwen.com/subject/rtfgvftx.html