ASP.NET Core 中的响应压缩

作者:Luke Latham

网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。

查看或下载示例代码如何下载

何时使用响应压缩中间件

在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。

使用响应压缩中间件:

响应压缩

通常,任何未进行本机压缩的响应都可以从响应压缩中获益。 不以本机方式压缩的响应通常包括: CSS、JavaScript、HTML、XML 和 JSON。 不应压缩本机压缩的资产,例如 PNG 文件。 如果尝试进一步压缩本机压缩的响应,则可能会相形见绌处理压缩所需的时间,从而减少大小和传输时间的任何小部分。 不要压缩小于大约150-1000 字节的文件(具体取决于文件的内容和压缩的效率)。 压缩小文件的开销可能会产生比未压缩文件更大的压缩文件。

如果客户端可以处理压缩的内容,则客户端必须通过请求发送 Accept-Encoding 标头来通知服务器的功能。 当服务器发送压缩内容时,它必须在 Content-Encoding 标头中包括有关如何对压缩的响应进行编码的信息。 下表显示了中间件支持的内容编码称号。

Accept-Encoding 标头值 支持的中间件 说明
br 是(默认值) Brotli 压缩数据格式
deflate DEFLATE 压缩数据格式
exi W3C 高效 XML 交换
gzip Gzip 文件格式
identity "无编码" 标识符:不能对响应进行编码。
pack200-gzip Java 存档的网络传输格式
* 未显式请求任何可用内容编码

有关详细信息,请参阅IANA 官方内容编码列表

中间件允许您为自定义 Accept-Encoding 标头值添加更多压缩提供程序。 有关详细信息,请参阅下面的自定义提供程序

当客户端发送时,中间件能够对质量值(qvalue、q)加权作出反应,以确定压缩方案的优先级。 有关详细信息,请参阅RFC 7231:接受编码

压缩算法会在压缩速度与压缩效率之间进行权衡。 此上下文的有效性是指压缩后的输出大小。 最小大小是通过最佳压缩来实现的。

下表介绍了请求、发送、缓存和接收压缩内容所涉及的标头。

标头 角色
Accept-Encoding 从客户端发送到服务器,以指示客户端可接受的内容编码方案。
Content-Encoding 从服务器发送到客户端,以指示有效负载中内容的编码。
Content-Length 进行压缩时,会删除 Content-Length 的标头,因为在对响应进行压缩时,正文内容会发生更改。
Content-MD5 进行压缩时,会删除 Content-MD5 标头,因为正文内容已更改,并且哈希不再有效。
Content-Type 指定内容的 MIME 类型。 每个响应都应指定其 Content-Type 中间件会检查此值以确定是否应压缩响应。 中间件指定了一组可进行编码的默认 MIME 类型,但你可以替换或添加 MIME 类型。
Vary 当服务器将 Accept-Encoding 的值发送到客户端和代理时,Vary 标头将根据请求的 Accept-Encoding 标头的值向客户端或代理指示它应缓存(变化)的响应。 Vary: Accept-Encoding 标头返回内容的结果是,压缩的和未压缩的响应都单独进行缓存。

浏览用于示例应用的响应压缩中间件功能。 该示例演示:

  • 使用 Gzip 和自定义压缩提供程序的应用程序响应的压缩。
  • 如何将 MIME 类型添加到 MIME 类型的默认列表以进行压缩。

响应压缩中间件由AspNetCore. ResponseCompression包提供,后者隐式包含在 ASP.NET Core 应用中。

配置

下面的代码演示如何为默认 MIME 类型和压缩提供程序(BrotliGzip)启用响应压缩中间件:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

注:

  • 必须在压缩响应的任何中间件之前调用 app.UseResponseCompression 有关详细信息,请参阅 ASP.NET Core 中间件
  • 使用FiddlerFirebugPostman等工具设置 Accept-Encoding 请求标头,并研究响应标头、大小和正文。

将请求提交到没有 Accept-Encoding 标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-EncodingVary 标头。

Fiddler 窗口显示请求的结果,无需接受编码标头。

将请求提交到带有 Accept-Encoding: br 标头的示例应用(Brotli 压缩),并观察响应是否已压缩。 响应中存在 Content-EncodingVary 标头。

Fiddler 窗口,其中显示带有接受编码标头和值为 br 的请求的结果。

提供程序

Brotli 压缩提供程序

使用 BrotliCompressionProvider 压缩Brotli 压缩数据格式的响应。

如果未将压缩提供程序显式添加到 CompressionProviderCollection

  • 默认情况下,Brotli 压缩提供程序会随Gzip 压缩提供程序一起添加到压缩提供程序的数组中。
  • 当客户端支持 Brotli 压缩数据格式时,压缩默认为 Brotli 压缩。 如果客户端不支持 Brotli,则在客户端支持 Gzip 压缩时,压缩默认为 Gzip。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

在显式添加任何压缩提供程序时,必须添加 Brotoli 压缩提供程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

设置 BrotliCompressionProviderOptions的压缩级别。 Brotli 压缩提供程序默认为最快的压缩级别(CompressionLevel),这可能不会生成最有效的压缩。 如果需要最有效的压缩,请将中间件配置为最佳压缩。

Compression Level 说明
CompressionLevel 压缩应该尽快完成,即使生成的输出未以最佳方式压缩。
CompressionLevel. NoCompression 不应执行压缩。
CompressionLevel 即使压缩需要更长的时间,也应以最佳方式压缩响应。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<BrotliCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

Gzip 压缩提供程序

使用 GzipCompressionProvider 压缩具有Gzip 文件格式的响应。

如果未将压缩提供程序显式添加到 CompressionProviderCollection

  • 默认情况下,Gzip 压缩提供程序随Brotli 压缩提供程序一起添加到压缩提供程序的数组中。
  • 当客户端支持 Brotli 压缩数据格式时,压缩默认为 Brotli 压缩。 如果客户端不支持 Brotli,则在客户端支持 Gzip 压缩时,压缩默认为 Gzip。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

在显式添加任何压缩提供程序时,必须添加 Gzip 压缩提供程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

设置 GzipCompressionProviderOptions的压缩级别。 Gzip 压缩提供程序默认为最快的压缩级别(CompressionLevel),这可能不会生成最有效的压缩。 如果需要最有效的压缩,请将中间件配置为最佳压缩。

Compression Level 说明
CompressionLevel 压缩应该尽快完成,即使生成的输出未以最佳方式压缩。
CompressionLevel. NoCompression 不应执行压缩。
CompressionLevel 即使压缩需要更长的时间,也应以最佳方式压缩响应。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<GzipCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

自定义提供程序

ICompressionProvider创建自定义压缩实现。 EncodingName 表示此 ICompressionProvider 生成的内容编码。 中间件使用这些信息根据请求的 Accept-Encoding 标头中指定的列表来选择提供程序。

使用示例应用程序,客户端提交 Accept-Encoding: mycustomcompression 标头的请求。 中间件使用自定义压缩实现并返回 Content-Encoding: mycustomcompression 标头的响应。 客户端必须能够解压缩自定义编码,才能使自定义压缩实现正常运行。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}
public class CustomCompressionProvider : ICompressionProvider
{
    public string EncodingName => "mycustomcompression";
    public bool SupportsFlush => true;

    public Stream CreateStream(Stream outputStream)
    {
        // Create a custom compression stream wrapper here
        return outputStream;
    }
}

将请求提交到带有 Accept-Encoding: mycustomcompression 标头的示例应用,并观察响应标头。 响应中存在 VaryContent-Encoding 标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider 类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。

Fiddler 窗口,其中显示带有接受编码标头和值 mycustomcompression 的请求的结果。

MIME 类型

中间件为压缩指定了一组默认的 MIME 类型:

  • application/javascript
  • application/json
  • application/xml
  • text/css
  • text/html
  • text/json
  • text/plain
  • text/xml

用响应压缩中间件选项替换或追加 MIME 类型。 请注意,不支持通配符 MIME 类型,如 text/* 示例应用为 image/svg+xml 添加了 MIME 类型,并对 ASP.NET Core 横幅图像(横幅)进行压缩和服务。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

安全协议压缩

可以使用默认情况下禁用 EnableForHttps 选项控制安全连接上的压缩响应。 在动态生成的页面中使用压缩可能会导致安全问题,例如犯罪漏洞攻击。

添加 Vary 标头

根据 Accept-Encoding 标头压缩响应时,可能会有多个压缩版本的响应和未压缩的版本。 为了指示客户端和代理缓存有多个版本存在且应该存储,将使用 Accept-Encoding 的值添加 Vary 标头。 在 ASP.NET Core 2.0 或更高版本中,在对响应进行压缩时,中间件会自动添加 Vary 标头。

Nginx 反向代理后的中间件问题

当 Nginx 代理请求时,将删除 Accept-Encoding 标头。 删除 Accept-Encoding 标头会阻止中间件压缩响应。 有关详细信息,请参阅NGINX:压缩和解压缩 此问题通过Nginx 的传递压缩(aspnet/BasicMiddleware #123)进行跟踪。

使用 IIS 动态压缩

如果在要为应用禁用的服务器级别上配置了活动的 IIS 动态压缩模块,请使用web.config文件的附加功能禁用该模块。 有关详细信息,请参阅禁用 IIS 模块

故障排除

使用FiddlerFirebugPostman之类的工具,通过该工具,可以设置 Accept-Encoding 请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:

  • Accept-Encoding 标头存在,其值为 brgzip*或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为 identity,或者其质量值(qvalue,q)设置为0(零)。
  • 必须设置 MIME 类型(Content-Type),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。
  • 请求不能包含 Content-Range 标头。
  • 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。

其他资源

网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。

查看或下载示例代码如何下载

何时使用响应压缩中间件

在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。

使用响应压缩中间件:

响应压缩

通常,任何未进行本机压缩的响应都可以从响应压缩中获益。 不以本机方式压缩的响应通常包括: CSS、JavaScript、HTML、XML 和 JSON。 不应压缩本机压缩的资产,例如 PNG 文件。 如果尝试进一步压缩本机压缩的响应,则可能会相形见绌处理压缩所需的时间,从而减少大小和传输时间的任何小部分。 不要压缩小于大约150-1000 字节的文件(具体取决于文件的内容和压缩的效率)。 压缩小文件的开销可能会产生比未压缩文件更大的压缩文件。

如果客户端可以处理压缩的内容,则客户端必须通过请求发送 Accept-Encoding 标头来通知服务器的功能。 当服务器发送压缩内容时,它必须在 Content-Encoding 标头中包括有关如何对压缩的响应进行编码的信息。 下表显示了中间件支持的内容编码称号。

Accept-Encoding 标头值 支持的中间件 说明
br 是(默认值) Brotli 压缩数据格式
deflate DEFLATE 压缩数据格式
exi W3C 高效 XML 交换
gzip Gzip 文件格式
identity "无编码" 标识符:不能对响应进行编码。
pack200-gzip Java 存档的网络传输格式
* 未显式请求任何可用内容编码

有关详细信息,请参阅IANA 官方内容编码列表

中间件允许您为自定义 Accept-Encoding 标头值添加更多压缩提供程序。 有关详细信息,请参阅下面的自定义提供程序

当客户端发送时,中间件能够对质量值(qvalue、q)加权作出反应,以确定压缩方案的优先级。 有关详细信息,请参阅RFC 7231:接受编码

压缩算法会在压缩速度与压缩效率之间进行权衡。 此上下文的有效性是指压缩后的输出大小。 最小大小是通过最佳压缩来实现的。

下表介绍了请求、发送、缓存和接收压缩内容所涉及的标头。

标头 角色
Accept-Encoding 从客户端发送到服务器,以指示客户端可接受的内容编码方案。
Content-Encoding 从服务器发送到客户端,以指示有效负载中内容的编码。
Content-Length 进行压缩时,会删除 Content-Length 的标头,因为在对响应进行压缩时,正文内容会发生更改。
Content-MD5 进行压缩时,会删除 Content-MD5 标头,因为正文内容已更改,并且哈希不再有效。
Content-Type 指定内容的 MIME 类型。 每个响应都应指定其 Content-Type 中间件会检查此值以确定是否应压缩响应。 中间件指定了一组可进行编码的默认 MIME 类型,但你可以替换或添加 MIME 类型。
Vary 当服务器将 Accept-Encoding 的值发送到客户端和代理时,Vary 标头将根据请求的 Accept-Encoding 标头的值向客户端或代理指示它应缓存(变化)的响应。 Vary: Accept-Encoding 标头返回内容的结果是,压缩的和未压缩的响应都单独进行缓存。

浏览用于示例应用的响应压缩中间件功能。 该示例演示:

  • 使用 Gzip 和自定义压缩提供程序的应用程序响应的压缩。
  • 如何将 MIME 类型添加到 MIME 类型的默认列表以进行压缩。

若要将中间件包含在项目中,请添加对AspNetCore 元包的引用,其中包括AspNetCore. ResponseCompression包。

配置

下面的代码演示如何为默认 MIME 类型和压缩提供程序(BrotliGzip)启用响应压缩中间件:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

注:

  • 必须在压缩响应的任何中间件之前调用 app.UseResponseCompression 有关详细信息,请参阅 ASP.NET Core 中间件
  • 使用FiddlerFirebugPostman等工具设置 Accept-Encoding 请求标头,并研究响应标头、大小和正文。

将请求提交到没有 Accept-Encoding 标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-EncodingVary 标头。

Fiddler 窗口显示请求的结果,无需接受编码标头。

将请求提交到带有 Accept-Encoding: br 标头的示例应用(Brotli 压缩),并观察响应是否已压缩。 响应中存在 Content-EncodingVary 标头。

Fiddler 窗口,其中显示带有接受编码标头和值为 br 的请求的结果。

提供程序

Brotli 压缩提供程序

使用 BrotliCompressionProvider 压缩Brotli 压缩数据格式的响应。

如果未将压缩提供程序显式添加到 CompressionProviderCollection

  • 默认情况下,Brotli 压缩提供程序会随Gzip 压缩提供程序一起添加到压缩提供程序的数组中。
  • 当客户端支持 Brotli 压缩数据格式时,压缩默认为 Brotli 压缩。 如果客户端不支持 Brotli,则在客户端支持 Gzip 压缩时,压缩默认为 Gzip。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

在显式添加任何压缩提供程序时,必须添加 Brotoli 压缩提供程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

设置 BrotliCompressionProviderOptions的压缩级别。 Brotli 压缩提供程序默认为最快的压缩级别(CompressionLevel),这可能不会生成最有效的压缩。 如果需要最有效的压缩,请将中间件配置为最佳压缩。

Compression Level 说明
CompressionLevel 压缩应该尽快完成,即使生成的输出未以最佳方式压缩。
CompressionLevel. NoCompression 不应执行压缩。
CompressionLevel 即使压缩需要更长的时间,也应以最佳方式压缩响应。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<BrotliCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

Gzip 压缩提供程序

使用 GzipCompressionProvider 压缩具有Gzip 文件格式的响应。

如果未将压缩提供程序显式添加到 CompressionProviderCollection

  • 默认情况下,Gzip 压缩提供程序随Brotli 压缩提供程序一起添加到压缩提供程序的数组中。
  • 当客户端支持 Brotli 压缩数据格式时,压缩默认为 Brotli 压缩。 如果客户端不支持 Brotli,则在客户端支持 Gzip 压缩时,压缩默认为 Gzip。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

在显式添加任何压缩提供程序时,必须添加 Gzip 压缩提供程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

设置 GzipCompressionProviderOptions的压缩级别。 Gzip 压缩提供程序默认为最快的压缩级别(CompressionLevel),这可能不会生成最有效的压缩。 如果需要最有效的压缩,请将中间件配置为最佳压缩。

Compression Level 说明
CompressionLevel 压缩应该尽快完成,即使生成的输出未以最佳方式压缩。
CompressionLevel. NoCompression 不应执行压缩。
CompressionLevel 即使压缩需要更长的时间,也应以最佳方式压缩响应。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<GzipCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

自定义提供程序

ICompressionProvider创建自定义压缩实现。 EncodingName 表示此 ICompressionProvider 生成的内容编码。 中间件使用这些信息根据请求的 Accept-Encoding 标头中指定的列表来选择提供程序。

使用示例应用程序,客户端提交 Accept-Encoding: mycustomcompression 标头的请求。 中间件使用自定义压缩实现并返回 Content-Encoding: mycustomcompression 标头的响应。 客户端必须能够解压缩自定义编码,才能使自定义压缩实现正常运行。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}
public class CustomCompressionProvider : ICompressionProvider
{
    public string EncodingName => "mycustomcompression";
    public bool SupportsFlush => true;

    public Stream CreateStream(Stream outputStream)
    {
        // Create a custom compression stream wrapper here
        return outputStream;
    }
}

将请求提交到带有 Accept-Encoding: mycustomcompression 标头的示例应用,并观察响应标头。 响应中存在 VaryContent-Encoding 标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider 类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。

Fiddler 窗口,其中显示带有接受编码标头和值 mycustomcompression 的请求的结果。

MIME 类型

中间件为压缩指定了一组默认的 MIME 类型:

  • application/javascript
  • application/json
  • application/xml
  • text/css
  • text/html
  • text/json
  • text/plain
  • text/xml

用响应压缩中间件选项替换或追加 MIME 类型。 请注意,不支持通配符 MIME 类型,如 text/* 示例应用为 image/svg+xml 添加了 MIME 类型,并对 ASP.NET Core 横幅图像(横幅)进行压缩和服务。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

安全协议压缩

可以使用默认情况下禁用 EnableForHttps 选项控制安全连接上的压缩响应。 在动态生成的页面中使用压缩可能会导致安全问题,例如犯罪漏洞攻击。

添加 Vary 标头

根据 Accept-Encoding 标头压缩响应时,可能会有多个压缩版本的响应和未压缩的版本。 为了指示客户端和代理缓存有多个版本存在且应该存储,将使用 Accept-Encoding 的值添加 Vary 标头。 在 ASP.NET Core 2.0 或更高版本中,在对响应进行压缩时,中间件会自动添加 Vary 标头。

Nginx 反向代理后的中间件问题

当 Nginx 代理请求时,将删除 Accept-Encoding 标头。 删除 Accept-Encoding 标头会阻止中间件压缩响应。 有关详细信息,请参阅NGINX:压缩和解压缩 此问题通过Nginx 的传递压缩(aspnet/BasicMiddleware #123)进行跟踪。

使用 IIS 动态压缩

如果在要为应用禁用的服务器级别上配置了活动的 IIS 动态压缩模块,请使用web.config文件的附加功能禁用该模块。 有关详细信息,请参阅禁用 IIS 模块

故障排除

使用FiddlerFirebugPostman之类的工具,通过该工具,可以设置 Accept-Encoding 请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:

  • Accept-Encoding 标头存在,其值为 brgzip*或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为 identity,或者其质量值(qvalue,q)设置为0(零)。
  • 必须设置 MIME 类型(Content-Type),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。
  • 请求不能包含 Content-Range 标头。
  • 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。

其他资源

网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。

查看或下载示例代码如何下载

何时使用响应压缩中间件

在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。

使用响应压缩中间件:

响应压缩

通常,任何未进行本机压缩的响应都可以从响应压缩中获益。 不以本机方式压缩的响应通常包括: CSS、JavaScript、HTML、XML 和 JSON。 不应压缩本机压缩的资产,例如 PNG 文件。 如果尝试进一步压缩本机压缩的响应,则可能会相形见绌处理压缩所需的时间,从而减少大小和传输时间的任何小部分。 不要压缩小于大约150-1000 字节的文件(具体取决于文件的内容和压缩的效率)。 压缩小文件的开销可能会产生比未压缩文件更大的压缩文件。

如果客户端可以处理压缩的内容,则客户端必须通过请求发送 Accept-Encoding 标头来通知服务器的功能。 当服务器发送压缩内容时,它必须在 Content-Encoding 标头中包括有关如何对压缩的响应进行编码的信息。 下表显示了中间件支持的内容编码称号。

Accept-Encoding 标头值 支持的中间件 说明
br Brotli 压缩数据格式
deflate DEFLATE 压缩数据格式
exi W3C 高效 XML 交换
gzip 是(默认值) Gzip 文件格式
identity "无编码" 标识符:不能对响应进行编码。
pack200-gzip Java 存档的网络传输格式
* 未显式请求任何可用内容编码

有关详细信息,请参阅IANA 官方内容编码列表

中间件允许您为自定义 Accept-Encoding 标头值添加更多压缩提供程序。 有关详细信息,请参阅下面的自定义提供程序

当客户端发送时,中间件能够对质量值(qvalue、q)加权作出反应,以确定压缩方案的优先级。 有关详细信息,请参阅RFC 7231:接受编码

压缩算法会在压缩速度与压缩效率之间进行权衡。 此上下文的有效性是指压缩后的输出大小。 最小大小是通过最佳压缩来实现的。

下表介绍了请求、发送、缓存和接收压缩内容所涉及的标头。

标头 角色
Accept-Encoding 从客户端发送到服务器,以指示客户端可接受的内容编码方案。
Content-Encoding 从服务器发送到客户端,以指示有效负载中内容的编码。
Content-Length 进行压缩时,会删除 Content-Length 的标头,因为在对响应进行压缩时,正文内容会发生更改。
Content-MD5 进行压缩时,会删除 Content-MD5 标头,因为正文内容已更改,并且哈希不再有效。
Content-Type 指定内容的 MIME 类型。 每个响应都应指定其 Content-Type 中间件会检查此值以确定是否应压缩响应。 中间件指定了一组可进行编码的默认 MIME 类型,但你可以替换或添加 MIME 类型。
Vary 当服务器将 Accept-Encoding 的值发送到客户端和代理时,Vary 标头将根据请求的 Accept-Encoding 标头的值向客户端或代理指示它应缓存(变化)的响应。 Vary: Accept-Encoding 标头返回内容的结果是,压缩的和未压缩的响应都单独进行缓存。

浏览用于示例应用的响应压缩中间件功能。 该示例演示:

  • 使用 Gzip 和自定义压缩提供程序的应用程序响应的压缩。
  • 如何将 MIME 类型添加到 MIME 类型的默认列表以进行压缩。

若要将中间件包含在项目中,请添加对AspNetCore 元包的引用,其中包括AspNetCore. ResponseCompression包。

配置

下面的代码演示如何为默认 MIME 类型和Gzip 压缩提供程序启用响应压缩中间件:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

注:

  • 必须在压缩响应的任何中间件之前调用 app.UseResponseCompression 有关详细信息,请参阅 ASP.NET Core 中间件
  • 使用FiddlerFirebugPostman等工具设置 Accept-Encoding 请求标头,并研究响应标头、大小和正文。

将请求提交到没有 Accept-Encoding 标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-EncodingVary 标头。

Fiddler 窗口显示请求的结果,无需接受编码标头。

将请求提交到带有 Accept-Encoding: gzip 标头的示例应用,并观察响应是否已压缩。 响应中存在 Content-EncodingVary 标头。

显示带有接受编码标头和值 gzip 的请求结果的 Fiddler 窗口。

提供程序

Gzip 压缩提供程序

使用 GzipCompressionProvider 压缩具有Gzip 文件格式的响应。

如果未将压缩提供程序显式添加到 CompressionProviderCollection

  • 默认情况下,将 Gzip 压缩提供程序添加到压缩提供程序的数组。
  • 当客户端支持 Gzip 压缩时,压缩默认为 Gzip。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

在显式添加任何压缩提供程序时,必须添加 Gzip 压缩提供程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

设置 GzipCompressionProviderOptions的压缩级别。 Gzip 压缩提供程序默认为最快的压缩级别(CompressionLevel),这可能不会生成最有效的压缩。 如果需要最有效的压缩,请将中间件配置为最佳压缩。

Compression Level 说明
CompressionLevel 压缩应该尽快完成,即使生成的输出未以最佳方式压缩。
CompressionLevel. NoCompression 不应执行压缩。
CompressionLevel 即使压缩需要更长的时间,也应以最佳方式压缩响应。
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

    services.Configure<GzipCompressionProviderOptions>(options => 
    {
        options.Level = CompressionLevel.Fastest;
    });
}

自定义提供程序

ICompressionProvider创建自定义压缩实现。 EncodingName 表示此 ICompressionProvider 生成的内容编码。 中间件使用这些信息根据请求的 Accept-Encoding 标头中指定的列表来选择提供程序。

使用示例应用程序,客户端提交 Accept-Encoding: mycustomcompression 标头的请求。 中间件使用自定义压缩实现并返回 Content-Encoding: mycustomcompression 标头的响应。 客户端必须能够解压缩自定义编码,才能使自定义压缩实现正常运行。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}
public class CustomCompressionProvider : ICompressionProvider
{
    public string EncodingName => "mycustomcompression";
    public bool SupportsFlush => true;

    public Stream CreateStream(Stream outputStream)
    {
        // Create a custom compression stream wrapper here
        return outputStream;
    }
}

将请求提交到带有 Accept-Encoding: mycustomcompression 标头的示例应用,并观察响应标头。 响应中存在 VaryContent-Encoding 标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider 类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。

Fiddler 窗口,其中显示带有接受编码标头和值 mycustomcompression 的请求的结果。

MIME 类型

中间件为压缩指定了一组默认的 MIME 类型:

  • application/javascript
  • application/json
  • application/xml
  • text/css
  • text/html
  • text/json
  • text/plain
  • text/xml

用响应压缩中间件选项替换或追加 MIME 类型。 请注意,不支持通配符 MIME 类型,如 text/* 示例应用为 image/svg+xml 添加了 MIME 类型,并对 ASP.NET Core 横幅图像(横幅)进行压缩和服务。

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes = 
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

安全协议压缩

可以使用默认情况下禁用 EnableForHttps 选项控制安全连接上的压缩响应。 在动态生成的页面中使用压缩可能会导致安全问题,例如犯罪漏洞攻击。

添加 Vary 标头

根据 Accept-Encoding 标头压缩响应时,可能会有多个压缩版本的响应和未压缩的版本。 为了指示客户端和代理缓存有多个版本存在且应该存储,将使用 Accept-Encoding 的值添加 Vary 标头。 在 ASP.NET Core 2.0 或更高版本中,在对响应进行压缩时,中间件会自动添加 Vary 标头。

Nginx 反向代理后的中间件问题

当 Nginx 代理请求时,将删除 Accept-Encoding 标头。 删除 Accept-Encoding 标头会阻止中间件压缩响应。 有关详细信息,请参阅NGINX:压缩和解压缩 此问题通过Nginx 的传递压缩(aspnet/BasicMiddleware #123)进行跟踪。

使用 IIS 动态压缩

如果在要为应用禁用的服务器级别上配置了活动的 IIS 动态压缩模块,请使用web.config文件的附加功能禁用该模块。 有关详细信息,请参阅禁用 IIS 模块

故障排除

使用FiddlerFirebugPostman之类的工具,通过该工具,可以设置 Accept-Encoding 请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:

  • Accept-Encoding 标头存在,其值为 gzip*或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为 identity,或者其质量值(qvalue,q)设置为0(零)。
  • 必须设置 MIME 类型(Content-Type),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。
  • 请求不能包含 Content-Range 标头。
  • 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。

其他资源

上一篇:使用 ASP.NET Core 中的 ObjectPool 对象重用

下一篇:性能诊断工具

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程