对一个网站的速度性能优化方法之一就是对请求数据的压缩,请求安全性提高就是数据的加密。其实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等。
网友评论