ASP.NET Core 中的请求解压缩

作者:David Acker

请求解压缩中间件:

  • 允许 API 终结点接受包含压缩内容的请求。
  • 使用 Content-Encoding HTTP 标头自动识别和解压缩包含压缩内容的请求。
  • 无需编写代码来处理压缩的请求。

当请求上的 Content-Encoding 标头值与可用的解压缩提供程序之一匹配时,中间件:

  • 使用匹配的提供程序将 HttpRequest.Body 包装在适当的解压缩流中。
  • 删除 Content-Encoding 标头,指示请求正文不再压缩。

请求解压缩中间件会忽略不包含 Content-Encoding 标头的请求。

解压缩:

  • 在读取请求正文时发生。 也就是说,解压缩发生在模型绑定的终结点上。 请求正文不会预先解压缩。
  • 尝试读取解压缩的请求正文时,如果该请求正文的压缩数据对指定的 Content-Encoding 无效,则会引发异常。 Brotli 可以引发 System.InvalidOperationException:Decoder ran into invalid data. Deflate 和 GZip 可以引发 System.IO.InvalidDataException:The archive entry was compressed using an unsupported compression method.

如果中间件遇到包含压缩内容但无法解压缩的请求,则会将请求传递到管道中的下一个委托。 例如,具有不受支持的 Content-Encoding 标头值或多个 Content-Encoding 标头值的请求将传递到管道中的下一个委托。

配置

以下代码使用 AddRequestDecompression(IServiceCollection)UseRequestDecompression默认Content-Encoding 类型启用请求解压缩:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRequestDecompression();

var app = builder.Build();

app.UseRequestDecompression();

app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body));

app.Run();

默认解压缩提供程序

下表中列出了默认情况下请求解压缩中间件支持的 Content-Encoding 标头值:

Content-Encoding 标头值 说明
br Brotli 压缩数据格式
deflate DEFLATE 压缩数据格式
gzip Gzip 文件格式

自定义解压缩提供程序

可以通过创建实现 IDecompressionProvider 的自定义解压缩提供程序类来添加对自定义编码的支持:

public class CustomDecompressionProvider : IDecompressionProvider
{
    public Stream GetDecompressionStream(Stream stream)
    {
        // Perform custom decompression logic here
        return stream;
    }
}

自定义解压缩提供程序连同相应的 Content-Encoding 标头值一起注册到 RequestDecompressionOptions

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRequestDecompression(options =>
{
    options.DecompressionProviders.Add("custom", new CustomDecompressionProvider());
});

var app = builder.Build();

app.UseRequestDecompression();

app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body));

app.Run();

请求大小限制

为了防范 zip 炸弹或解压缩炸弹

  • 解压缩的请求正文的最大大小限制为终结点或服务器强制实施的请求正文大小限制。
  • 如果从解压缩的请求正文流中读取的字节数超出限制,则会引发 InvalidOperationException 以防止从流读取其他字节。

根据优先级顺序,终结点的最大请求大小由以下方式设置:

  1. IRequestSizeLimitMetadata.MaxRequestBodySize,例如 MVC 终结点的 RequestSizeLimitAttributeDisableRequestSizeLimitAttribute
  2. 全局服务器大小限制 IHttpMaxRequestBodySizeFeature.MaxRequestBodySize。 可以使用 IHttpMaxRequestBodySizeFeature.MaxRequestBodySize 覆盖每个请求的 MaxRequestBodySize,但默认为 Web 服务器实现配置的限制。
Web 服务器实现 MaxRequestBodySize 配置
HTTP.sys HttpSysOptions.MaxRequestBodySize
IIS IISServerOptions.MaxRequestBodySize
Kestrel KestrelServerLimits.MaxRequestBodySize

警告

禁用请求正文大小限制会在不受控制的资源消耗方面造成安全风险,尤其是在正在缓冲请求正文时。 确保提供安全措施来缓解拒绝服务 (DoS) 攻击的风险。

其他资源