10

私は新しい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年後のexpiresヘッダーとtext/javascriptのコンテンツタイプが表示されます

web.configには、静的JSファイルで動作するgzipのコードがありますが、縮小されたバンドルでは動作していないようです。

<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で圧縮する方法はありますか?

4

3 に答える 3

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

次に、を使用GZipStyleBundleして元のクラスGZipScriptBundleを置き換えることができます: 、。元:BundleStyleBundleScriptBundle

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

よろしく

于 2014-03-31T10:51:52.870 に答える
11

お気づきのとおり、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 ;
    }
}

さて、ここに不幸な部分があります-このサンプルをテストする際に、私はそれが機能するのを妨げるバグを発見しました。元のデザインでは、人々は非常に単純なことを行うと予想されていました。そのため、BundleResponseは、コンテンツ(より具体的には文字列コンテンツ)とコンテンツタイプを設定できるプロパティを公開します。BundleContextはHttpContextのプロパティを公開します。これにより、合理的な人は、応答の追加のプロパティをそこに設定できると信じるようになります(上記のとおり)。ただし、これは2つの理由で誤解を招く可能性があります。

  1. バンドル変換は、バンドルの作成の一部として実行されます-バンドルの作成は、最初に参照されたときに行われます(ブラウザはスクリプトタグのsrc属性に従いますが、参照されません)が、ビューの呼び出しのように参照されますScripts.Renderヘルパーメソッド)。上記の私の例では、これは、gzipの値を持つコンテンツエンコーディングヘッダーが、バンドルのヘルパーメソッドを使用してリンクを生成するビューで最初のページに設定されることを意味します-実際のHTTPコンテンツがgzipで圧縮されていない場合は、ブラウザはHTTPコンテンツをデコードできないため、エラーが発生します。

  2. #1が問題ではなかったとしても、バンドルは作成後すぐにASP.NETキャッシュに入れられるため、このコードパスは1回だけ実行されます。

次のバージョンのフレームワークでは、HTTPコンテキストを含まない(つまり、簡単にキャッシュできる)HTTP応答メッセージのすべての(理想的には)側面を指定できるようにするための設計を精査しています。

1つの追加のメモ。カスタムバンドル変換を提供するには、ScriptBundle/StyleBundleではなくBundleのインスタンスの作成にフォールバックする必要があります。これらのクラスは、実際には、事前構成されたバンドル変換を備えたバンドルの単なる省略型です。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);
于 2012-07-05T22:58:17.520 に答える
4

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

設定に登録します

  <system.webServer>
    <modules>
        <add name="Gzip" type="Gecko.Web.GzipModule" />
    </modules>
于 2012-08-04T23:49:04.813 に答える