11

我使用新System.Web.Optimization并创造了这样的捆绑:的GZip 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")) 

在我看来,我已经加入这个

@System.Web.Optimization.Scripts.Render("~/bundles/BaseJS") 

在提琴手的URL会遇到过期1年的过期头文件和文本的内容类型/ javascript

在web.config中,我有一些gzip代码用于处理静态JS文件,但它没有' Ť似乎在缩小的捆绑上。

<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> 

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

+0

我想这可能与iBundleTransform但我不知道怎么样。 https://twitter.com/ericdc1/status/219850852364599298 – ericdc

回答

12

如上所述,通过创建实现IBundleTransform的类来创建自定义捆绑转换是正确的方法。例如,下面是一个例子包变换使用SharpZipLib(via 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 ; 
    } 
} 

现在,这里是不幸的一部分 - 在测试了这个例子,我发现,这将阻止它的错误加工。原始设计预计人们会做很简单的事情 - 因此,BundleResponse公开了允许您设置内容(更具体地说,字符串内容)和内容类型的属性。 BundleContext暴露了HttpContext的一个属性,这会导致一个合理的人相信可以在那里设置响应的附加属性(如上所示)。然而,这是一个误导原因有二:

  1. 包变换的运行,创建该包的一部分 - 创建束发生在第一次引用(不会解除引用,如,浏览器跟随脚本标记中的src属性 - 但引用视图调用Scripts.Render辅助方法)。在我上面的例子中,这意味着一个值为gzip的内容编码头将被设置在第一页上,该视图使用绑定的辅助方法来生成一个链接 - 如果实际的HTTP内容没有被压缩,由于浏览器无法解码HTTP内容,因此会发生错误。

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

我们在框架的下一个版本,使您可以指定一个免费的HTTP上下文的HTTP响应消息的所有(理想)方面采取了认真审视设计(这意味着它很容易被缓存)。

一个附加说明。要提供自定义捆绑转换,您需要重新创建一个Bundle实例,而不是ScriptBundle/StyleBundle。这些类实际上只是具有预配置捆绑转换的捆绑的简写类型。要创建一个基于包束,你会做类似如下:

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); 
+4

事实证明,IIS动态内容压缩可以在没有所有仪式的情况下执行此操作。在我的情况下,我不得不IISCreset安装DCC后,使其工作,所以我误以为system.web.optimization需要干预gzip,但它没有。 – ericdc

+0

您写下“我们正在仔细研究下一个框架版本的设计......”,所以我想你是ASP.NET团队的成员。您是否打算在下一个版本中允许字节内容?这对于图像捆绑(精灵)非常有用。 – JohannesH

+2

这是否曾在System.Web.Optimizations中解决?我处于无法使用IIS压缩的环境下,所以这似乎是除了使用HttpModule之外唯一可行的方法。 – kkara

5

它可以使用HTTP模块

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); 
     } 
    } 
} 

实现和配置

<system.webServer> 
    <modules> 
     <add name="Gzip" type="Gecko.Web.GzipModule" /> 
    </modules> 
+2

确实如此,但现在将针对所有请求运行,而不仅仅是捆绑。 –

11

注册它随着最新的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; 
    } 
} 

然后你可以使用GZipStyleBundleGZipScriptBundle取代原来Bundle类:StyleBundleScriptBundle。例如:

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(...)); 
    } 
} 

问候