- 全球化与本土化
- 性能
- 高级
ASP.NET Core 中的响应压缩
作者:Luke Latham
网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。
何时使用响应压缩中间件
在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。
使用响应压缩中间件:
- 无法使用以下基于服务器的压缩技术:
- 直接在上托管:
- Http.sys 服务器(以前称为 WebListener)
- 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 类型和压缩提供程序(Brotli和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 中间件。 - 使用Fiddler、 Firebug或Postman等工具设置
Accept-Encoding
请求标头,并研究响应标头、大小和正文。
将请求提交到没有 Accept-Encoding
标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-Encoding
和 Vary
标头。
将请求提交到带有 Accept-Encoding: br
标头的示例应用(Brotli 压缩),并观察响应是否已压缩。 响应中存在 Content-Encoding
和 Vary
标头。
提供程序
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
标头的示例应用,并观察响应标头。 响应中存在 Vary
和 Content-Encoding
标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider
类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。
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 模块。
故障排除
使用Fiddler、 Firebug或Postman之类的工具,通过该工具,可以设置 Accept-Encoding
请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:
Accept-Encoding
标头存在,其值为br
、gzip
、*
或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为identity
,或者其质量值(qvalue,q
)设置为0(零)。- 必须设置 MIME 类型(
Content-Type
),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。 - 请求不能包含
Content-Range
标头。 - 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。
其他资源
网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。
何时使用响应压缩中间件
在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。
使用响应压缩中间件:
- 无法使用以下基于服务器的压缩技术:
- 直接在上托管:
- Http.sys 服务器(以前称为 WebListener)
- 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 类型和压缩提供程序(Brotli和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 中间件。 - 使用Fiddler、 Firebug或Postman等工具设置
Accept-Encoding
请求标头,并研究响应标头、大小和正文。
将请求提交到没有 Accept-Encoding
标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-Encoding
和 Vary
标头。
将请求提交到带有 Accept-Encoding: br
标头的示例应用(Brotli 压缩),并观察响应是否已压缩。 响应中存在 Content-Encoding
和 Vary
标头。
提供程序
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
标头的示例应用,并观察响应标头。 响应中存在 Vary
和 Content-Encoding
标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider
类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。
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 模块。
故障排除
使用Fiddler、 Firebug或Postman之类的工具,通过该工具,可以设置 Accept-Encoding
请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:
Accept-Encoding
标头存在,其值为br
、gzip
、*
或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为identity
,或者其质量值(qvalue,q
)设置为0(零)。- 必须设置 MIME 类型(
Content-Type
),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。 - 请求不能包含
Content-Range
标头。 - 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。
其他资源
网络带宽是一种有限的资源。 减小响应大小通常会显著提高应用程序的响应能力。 减少负载大小的一种方法是压缩应用的响应。
何时使用响应压缩中间件
在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。 中间件的性能与服务器模块的性能可能不一致。 Http.sys 服务器服务器和Kestrel服务器当前不提供内置的压缩支持。
使用响应压缩中间件:
- 无法使用以下基于服务器的压缩技术:
- 直接在上托管:
- Http.sys 服务器(以前称为 WebListener)
- 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 中间件。 - 使用Fiddler、 Firebug或Postman等工具设置
Accept-Encoding
请求标头,并研究响应标头、大小和正文。
将请求提交到没有 Accept-Encoding
标头的示例应用,并观察响应是否未压缩。 响应中不存在 Content-Encoding
和 Vary
标头。
将请求提交到带有 Accept-Encoding: gzip
标头的示例应用,并观察响应是否已压缩。 响应中存在 Content-Encoding
和 Vary
标头。
提供程序
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
标头的示例应用,并观察响应标头。 响应中存在 Vary
和 Content-Encoding
标头。 示例不压缩响应正文(未显示)。 示例的 CustomCompressionProvider
类中没有压缩实现。 但是,该示例显示了实现此类压缩算法的位置。
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 模块。
故障排除
使用Fiddler、 Firebug或Postman之类的工具,通过该工具,可以设置 Accept-Encoding
请求标头并研究响应标头、大小和正文。 默认情况下,响应压缩中间件会压缩满足以下条件的响应:
Accept-Encoding
标头存在,其值为gzip
、*
或自定义编码,此值与已建立的自定义压缩提供程序匹配。 该值不能为identity
,或者其质量值(qvalue,q
)设置为0(零)。- 必须设置 MIME 类型(
Content-Type
),并且该类型必须与 ResponseCompressionOptions上配置的 MIME 类型匹配。 - 请求不能包含
Content-Range
标头。 - 除非在响应压缩中间件选项中配置了安全协议(https),否则请求必须使用不安全的协议(http)。 启用安全内容压缩时,请注意上面所述的危险。