asp.net core 系列之Performance的 Response compression(响应压缩)
本文,帮助了解响应压缩的一些知识及用法(大部分翻译于官网,英文水平有限,不准确之处,欢迎指正)。
什么是响应压缩?响应压缩简单的说就是为了减少网络带宽,而把返回的响应压缩,使之体积缩小,从而加快响应的一种技术(个人理解)
网络带宽是有限的资源。减少响应(response)的大小通常可以增加应用的响应性(即减少响应的大小可以加快响应的速度),这是很引人注目的(often dramatically).压缩(压缩compress)应用的响应可以减少装载的大小。
当使用响应压缩中间件时(Response Compression Middleware)
在IIS,Apache,Nginx中使用基于服务端的响应压缩技术。中间件的执行可能和服务端模块不匹配。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 Core的banner 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