asp.net core 系列之Performance的 Response compression(响应压缩)

本文,帮助了解响应压缩的一些知识及用法(大部分翻译于官网,英文水平有限,不准确之处,欢迎指正)。

什么是响应压缩?响应压缩简单的说就是为了减少网络带宽,而把返回的响应压缩,使之体积缩小,从而加快响应的一种技术(个人理解)

网络带宽是有限的资源。减少响应(response)的大小通常可以增加应用的响应性(即减少响应的大小可以加快响应的速度),这是很引人注目的(often dramatically).压缩(压缩compress)应用的响应可以减少装载的大小。

当使用响应压缩中间件时(Response Compression Middleware)

在IIS,ApacheNginx中使用基于服务端的响应压缩技术。中间件的执行可能和服务端模块不匹配。HTTP.sys Kestrel server目前没有提供内置的压缩支持。

什么时候使用Response Compression Middleware:

  • 不能使用下面的服务端压缩技术时:
    • IIS Dynamic Compression module (IIS 动态压缩模块)
    • Apache mod_deflate module (deflate:紧缩 )
    • Nginx Compression and Decompression
  • 部署运行在:
    • HTTP.sys server
    • Kestrel server

响应压缩(Response compression)

通常,任何不能自动压缩的响应都可以从响应压缩中获益。典型的不能自动压缩的响应包括:CSS, JavaScript, HTML, XML, 和JSON. 你不应该压缩自动压缩的文件,例如 PNG文件。如果你尝试更进一步压缩一个自动压缩的响应,那么任何小的额外的缩小和传送时间都将会显得黯然失色,等到它处理压缩, 不要压缩小于150-1000bytes文件(取决于文件的内容和压缩的效率)压缩小文件开销可以产生大于未压缩文件的压缩文件

当客户端可以处理压缩内容时,客户端必须通过发送请求头上的Accept-Encoding 通知服务器它的能力。当服务器发送压缩内容时,它必须在Content-Encoding 头中包含压缩的响应是怎么编码的内容。内容编码的指定是通过下表中展示的中间件支持的。

中间件允许你为自定义的Accept-Encoding 的头上的值增加额外的压缩提供者,中间件对于质量值的反应是很熟练的,质量值是被客户端发送的用来衡量优先处理压缩协议的。

压缩算法是受支配于压缩速度和压缩效率的一种平衡交易。效率关系到压缩之后的大小,最优压缩压缩出来的就是最小的。

涉及到请求,发送,缓存,接收压缩内容的头部在下表中有描述

 

利用sample app 探索响应压缩的功能。这个例子表明:

  •  应用的利用Gzip和自定义压缩提供者的压缩
  • 怎样增加MIME类型到默认的压缩的MIME类型的列表

Package

为了在项目中包含这个中间件,增加一个到 Microsoft.AspNetCore.App metapackage, 的引用,它包含 Microsoft.AspNetCore.ResponseCompression 包 

Configuration

下面的代码展示了怎样允许Response Compression Middleware , 对于默认的MIME类型和压缩提供者(Brotli Gzip):

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

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

注意:

  • App.UseResponseCompression 必须在app.UseMvc之前被调用

  • 用一个工具(例如Fiddler, Filrebug, Postman)来设置Accept-Encoding 请求头,并且研究响应头,大小和body

提交一个不携带Acccept-Encoding 头的请求到示例应用,并且观察到响应是未压缩的。Content-Encoding 和 Vary 头没有在响应中呈现。

 

提交一个带Accept-Encoding: br头的请求到示例应用。(Brotli compress)并且观察响应是压缩的。Content-Encoding Vary 在响应中呈现了。

Providers(提供者)

Brotli Compression Provider

使用BrotliCompressionProvider来压缩响应,使用Brotli compressed data format ( brotli compress 数据格式),

如果没有compression providers(压缩提供者)被明确的加到 CompressionProviderCollection中:

  • Brotli Compression Provider 默认被加到compression providers的数组中,和Gzip compression provider.
  • 当客户端支持Brotli compressed data format (Brotli 压缩数据格式)时,默认使用Brotli compression 压缩. 如果客户端不支持Brotli , 但是客户端支持Gzip 压缩时,会默认使用Gzip
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

Brotoli Compression Provider必须被添加,当任意compression provider 明确的被添加时。

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 Compression Provider默认使用的是最快的压缩级别( CompressionLevel.Fastest ), 这种级别可能不会产生最有效率的压缩。如果最有效率的压缩被需要时,可以为最佳的压缩配置中间件

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

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

Gzip Compression Provider

使用GzipCompressionProvider来压缩响应,用Gzip file format.(用Gzip 文件格式)

如果没有compression provider被明确的加入到CompressionProviderCollection中:

  • Gzip Compression Provider默认被添加到 压缩提供者数组中,并且还有Brotli Compression Provider.
  • 当客户端支持Brotli compressed data format (Brotli 压缩数据格式)时,默认使用Brotli compression 压缩. 如果客户端不支持Brotli , 但是客户端支持Gzip 压缩时,会默认使用Gzip 
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();
}

Gzip Compression Provider 必须被添加,当任意压缩提供者被明确的添加时:

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 Compression Provider默认使用的是最快的压缩级别( CompressionLevel.Fastest ), 这种级别可能不会产生最有效率的压缩。如果最有效率的压缩被需要时,可以为最佳的压缩配置中间件

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression();

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

Custom providers

通过实现ICompressionProvider接口创建自定义的压缩。EncodingName代表ICompressionProvider生成的内容编码(the content encoding). 中间件使用这个信息来选择provider,在请求的Accept-Encoding 头上的列表的基础上。

在示例项目上,客户端提交请求,带有Accept-Encoding: mycustomcompression头。中间件使用自定义的压缩实现并且返回带有Content-Encoding:mycustomcompression头的响应。客户端必须可以按顺序的解压自定义的编码( the custom encoding) ,对于一个自定义的压缩实现的工作。

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-Encodign:mycustomcompression头的请求到示例应用,并且观察响应头。响应中呈现出了Vary Content-Encoding头。The response body 没有被压缩在项目中。在示例项目的CustomCompressionProvider类中没有一个压缩实现。示例展示了你在哪里实现这样一个压缩算法。

MIME types

这个中间件指定一个默认的用于压缩的MIME types:

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

在Response Compression Middleware options上替换或者增加MIME types. 注意,带有通配符的MIME types, 例如 text/* 是不支持的。 示例应用中增加了一个MIME type image/svg+xml 并且压缩并且作用于ASP.NET Corebanner image ( banner,svg ).

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

Compression with secure protocol (带安全协议的压缩)

在安全连接上的压缩响应可以使用 EnableForHttps 项(option)来控制, 它默认是被禁用的, 在动态生成的页面上面使用压缩可能会导致安全问题, 例如  CRIME and BREACH  攻击。

Adding the Vary header

当压缩响应在Accept-Encoding 头上时, 那是可能会有多个压缩版本(compressed versions)的响应和一个不压缩的版本。为了指导客户端和代理(client and proxy)缓存多个存在的版本,并且存储,Vary 头是被加到Accept-Encoding 值。 在ASP.NET Core 2.0或者更新的版本,当响应被压缩时,中间件自动添加Vary 头。

Middleware issue when behind an Nginx reverse proxy (Nginx反向代理时中间件的问题)

当一个请求被Nginx代理时,Accept-Encoding 头被移除了, Accept-Encoding头的移除阻止了中间件压缩响应。更多的信息:NGINX: Compression and Decompression

Working with IIS dynamic compression

当你有一个激活的IIS动态压缩模块配置在服务器级别(at the server level), 你可能会想要在一个应用上禁止它,那么你可以在web.config文件中禁用它。更多的信息:Disabling IIS modules.  

 本文翻译于:https://docs.microsoft.com/en-us/aspnet/core/performance/response-compression?view=aspnetcore-2.2

 

 

 

 

 

posted @ 2019-06-15 09:03  Vincent-yuan  阅读(2662)  评论(0编辑  收藏  举报