GZip system.web.optimization捆绑

eri*_*cdc 11 asp.net-mvc-3 bundling-and-minification asp.net-optimization

我正在使用新的System.Web.Optimization并创建了一个这样的包:

bundles.Add(New ScriptBundle("~/bundles/BaseJS").Include(
                "~/Resources/Core/Javascripts/jquery-1.7.1.js",
                "~/Resources/Core/Javascripts/jquery-ui-1.8.16.js",
                "~/Resources/Core/Javascripts/jquery.validate.js",
                "~/Resources/Core/Javascripts/jquery.validate.unobtrusive.js",
                "~/Resources/Core/Javascripts/jquery.unobtrusive-ajax.js"))
Run Code Online (Sandbox Code Playgroud)

在我看来,我添加了这个

@System.Web.Optimization.Scripts.Render("~/bundles/BaseJS")
Run Code Online (Sandbox Code Playgroud)

在fiddler中,URL会遇到未来1年的过期标头和文本/ javascript的内容类型

在web.config中,我有一些gzip的代码正在处理静态JS文件,但它似乎没有在缩小的bundle上.

<staticContent>
  <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00"/>
  <remove fileExtension=".js"/>
  <mimeMap fileExtension=".js" mimeType="text/javascript"/>
</staticContent>
<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/>
<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
  <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
  <dynamicTypes>
    <add mimeType="text/*" enabled="true"/>
    <add mimeType="text/javascript" enabled="true"/>
  </dynamicTypes>
  <staticTypes>
    <add mimeType="text/*" enabled="true"/>
    <add mimeType="text/javascript" enabled="true"/>
  </staticTypes>
</httpCompression>
Run Code Online (Sandbox Code Playgroud)

有没有办法让渲染包gzip的内容?

How*_*ing 12

如您所述,通过创建实现IBundleTransform的类来创建自定义包变换是正确的方法.例如,以下是使用SharpZipLib(通过NuGet)进行GZip压缩的示例包变换:

public class GZipTransform : IBundleTransform 
{
    string _contentType;

    public GZipTransform(string contentType)
    {
        _contentType = contentType;
    }

    public void Process(BundleContext context, BundleResponse response)
    {
        var contentBytes = new UTF8Encoding().GetBytes(response.Content);

        var outputStream = new MemoryStream();
        var gzipOutputStream = new GZipOutputStream(outputStream);
        gzipOutputStream.Write(contentBytes, 0, contentBytes.Length);

        var outputBytes = outputStream.GetBuffer();
        response.Content = Convert.ToBase64String(outputBytes);


        // NOTE: this part is broken
        context.HttpContext.Response.Headers["Content-Encoding"] = "gzip";
        response.ContentType = _contentType ;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这是不幸的部分 - 在测试这个示例时,我发现了一个让它无法工作的错误.原始设计期望人们可以做很简单的事情 - 因此,BundleResponse公开了允许您设置内容(更具体地说,字符串内容)和内容类型的属性.BundleContext公开了HttpContext的一个属性,这将使一个合理的人相信可以在那里设置响应的其他属性(如上所示).但是,由于两个原因,这是误导性的:

  1. 捆绑转换作为创建捆绑包的一部分运行 - 并且在第一次引用捆绑包时会创建捆绑包(而不是取消引用,因为浏览器遵循脚本标记中的src属性 - 但是在视图调用中引用Scripts.Render帮助方法).在上面的示例中,这意味着将在第一页上设置具有值gzip的内容编码头,其中视图使用捆绑的帮助程序方法来生成链接 - 如果实际的HTTP内容未被gzip压缩,那么'由于浏览器无法解码HTTP内容,因此会收到错误.

  2. 即使#1不是问题,捆绑包也会在创建后立即放入ASP.NET缓存中 - 因此此代码路径只会执行一次.

我们正在仔细研究下一版本框架中的设计,以使您能够指定HTTP响应消息的所有(理想情况下)方面,这些方面没有HTTP上下文(意味着它很容易被缓存).

另外一个说明.要提供自定义包变换,您需要回退到创建Bundle而不是ScriptBundle/StyleBundle的实例.这些类实际上只是具有预配置捆绑转换的捆绑包的简写类型.要基于Bundle创建捆绑包,您可以执行以下操作:

var jqueryBundle = new Bundle("~/bundles/jqueryall", new GZipTransform("text/javascript"));
jqueryBundle.Include("~/Scripts/jquery-1.*",
    "~/Scripts/jquery-ui*",
    "~/Scripts/jquery.unobtrusive*",
    "~/Scripts/jquery.validate*");
bundles.Add(jqueryBundle);
Run Code Online (Sandbox Code Playgroud)

  • 事实证明,IIS动态内容压缩没有完成所有仪式.在我的情况下,我在安装DCC之后不得不使用IISReset以使其正常工作,因此我误以为system.web.optimization需要干预gzip,但事实并非如此. (4认同)
  • 这是否曾在System.Web.Optimizations中修复过?我在一个不能使用IIS压缩的环境中,所以这似乎是除了使用HttpModule之外唯一可行的方法. (2认同)

小智 12

有了最新版本ASP.NET Optimization (v1.1.2),该GZipTransform课程效果不佳.

我找到了一种自定义Bundle类的新方法,它将始终在响应之前压缩包内容(已转换和缓存):

public class GZipBundle : Bundle
{
    public GZipBundle(string virtualPath, params IBundleTransform[] transforms)
        : base(virtualPath, null, transforms) { }

    public override BundleResponse CacheLookup(BundleContext context)
    {
        if (null != context) GZipEncodePage(context.HttpContext);
        return base.CacheLookup(context);
    }

    // Sets up the current page or handler to use GZip through a Response.Filter.
    public static void GZipEncodePage(HttpContextBase httpContext)
    {
        if (null != httpContext && null != httpContext.Request && null != httpContext.Response
            && (null == httpContext.Response.Filter
            || !(httpContext.Response.Filter is GZipStream || httpContext.Response.Filter is DeflateStream)))
        {
            // Is GZip supported?
            string acceptEncoding = httpContext.Request.Headers["Accept-Encoding"];
            if (null != acceptEncoding
                && acceptEncoding.IndexOf(DecompressionMethods.GZip.ToString(), StringComparison.OrdinalIgnoreCase) >= 0)
            {
                httpContext.Response.Filter = new GZipStream(httpContext.Response.Filter, CompressionMode.Compress);
                httpContext.Response.AddHeader("Content-Encoding", DecompressionMethods.GZip.ToString().ToLowerInvariant());
            }
            else if (null != acceptEncoding
                && acceptEncoding.IndexOf(DecompressionMethods.Deflate.ToString(), StringComparison.OrdinalIgnoreCase) >= 0)
            {
                httpContext.Response.Filter = new DeflateStream(httpContext.Response.Filter, CompressionMode.Compress);
                httpContext.Response.AddHeader("Content-Encoding", DecompressionMethods.Deflate.ToString().ToLowerInvariant());
            }

            // Allow proxy servers to cache encoded and unencoded versions separately
            httpContext.Response.AppendHeader("Vary", "Content-Encoding");
        }
    }
}

// Represents a bundle that does CSS minification and GZip compression.
public sealed class GZipStyleBundle : GZipBundle
{
    public GZipStyleBundle(string virtualPath, params IBundleTransform[] transforms) : base(virtualPath, transforms) { }
}

// Represents a bundle that does JS minification and GZip compression.
public sealed class GZipScriptBundle : GZipBundle
{
    public GZipScriptBundle(string virtualPath, params IBundleTransform[] transforms)
        : base(virtualPath, transforms)
    {
        base.ConcatenationToken = ";" + Environment.NewLine;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用GZipStyleBundleGZipScriptBundle替换原来的Bundle类:StyleBundle, ScriptBundle. 例如:

public static class BundleConfig
{
    // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new GZipScriptBundle("~/bundles/jquery.js").Include(...));
        bundles.Add(new GZipScriptBundle("~/bundles/jquery-ui.js", new JsMinify()).Include(...));

        bundles.Add(new GZipStyleBundle("~/bundles/all.css", new CssMinify()).Include(...));
    }
}
Run Code Online (Sandbox Code Playgroud)

问候


小智 5

它可以使用HttpModule实现

public class GzipModule : IHttpModule
{
    #region IHttpModule Members

    public void Init(HttpApplication application)
    {
        application.BeginRequest += Application_BeginRequest;
    }

    public void Dispose()
    {
    }

    #endregion

    private void Application_BeginRequest(Object source, EventArgs e)
    {
        HttpContext context = HttpContext.Current;
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;
        string acceptEncoding = request.Headers["Accept-Encoding"];

        if (String.IsNullOrEmpty(acceptEncoding))
            return;

        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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并在配置中注册

  <system.webServer>
    <modules>
        <add name="Gzip" type="Gecko.Web.GzipModule" />
    </modules>
Run Code Online (Sandbox Code Playgroud)

  • 是的,但现在这将针对所有请求运行,而不仅仅是针对捆绑包. (2认同)