You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6 Web API如何获取Gzip压缩响应的大小?

获取ASP.NET Core 6中Gzip压缩后的响应体大小

直接读取Response.ContentLength会出错,原因是Gzip压缩是动态流式处理的,压缩后的响应流不支持直接获取预定义长度,且流会被压缩中间件封装为无法直接读取长度的包装流。以下是可行的实现方案:

1. 实现字节数跟踪流

创建一个包装流,用于统计写入到响应流的总字节数:

public class SizeTrackingStream : Stream
{
    private readonly Stream _innerStream;
    public long TotalBytesWritten { get; private set; }

    public SizeTrackingStream(Stream innerStream)
    {
        _innerStream = innerStream;
    }

    public override bool CanRead => _innerStream.CanRead;
    public override bool CanSeek => _innerStream.CanSeek;
    public override bool CanWrite => _innerStream.CanWrite;
    public override long Length => _innerStream.Length;
    public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; }

    public override void Flush() => _innerStream.Flush();
    public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count);
    public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
    public override void SetLength(long value) => _innerStream.SetLength(value);

    public override void Write(byte[] buffer, int offset, int count)
    {
        TotalBytesWritten += count;
        _innerStream.Write(buffer, offset, count);
    }

    public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
    {
        TotalBytesWritten += count;
        await _innerStream.WriteAsync(buffer, offset, count, cancellationToken);
    }
}

2. 编写响应大小跟踪中间件

通过中间件替换响应流为跟踪流,在压缩完成后获取字节数:

public class ResponseSizeMiddleware
{
    private readonly RequestDelegate _next;

    public ResponseSizeMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var originalStream = context.Response.Body;
        try
        {
            using var trackingStream = new SizeTrackingStream(originalStream);
            context.Response.Body = trackingStream;

            // 执行后续管道,让压缩中间件处理响应
            await _next(context);

            // 获取压缩后的响应大小
            var compressedSize = trackingStream.TotalBytesWritten;
            
            // 可选:将大小写入自定义响应头,返回给客户端
            context.Response.Headers.Add("X-Compressed-Size", compressedSize.ToString());
            
            // 可选:记录到日志(需注入ILogger)
            // _logger.LogInformation($"Compressed response size: {compressedSize} bytes");
            
            // 可选:存入HttpContext.Items,供控制器读取
            // context.Items["CompressedResponseSize"] = compressedSize;
        }
        finally
        {
            context.Response.Body = originalStream;
        }
    }
}

3. 正确注册中间件

在Program.cs中,必须将跟踪中间件注册在压缩中间件之后,确保捕获的是压缩后的响应流:

var builder = WebApplication.CreateBuilder(args);

// 添加压缩服务
builder.Services.AddControllers();
builder.Services.AddResponseCompression(options =>
{
    options.Providers.Add<GzipCompressionProvider>();
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });
});

var app = builder.Build();

// 注册顺序:先压缩中间件,再跟踪中间件
app.UseResponseCompression();
app.UseMiddleware<ResponseSizeMiddleware>();

app.MapControllers();

app.Run();

注意事项

  • 中间件顺序不可颠倒,否则捕获的是压缩前的响应大小。
  • 不要依赖Response.ContentLength属性,该值在动态压缩场景下会是null或不准确。
  • 如果需要在控制器中获取压缩大小,可通过HttpContext.Items["CompressedResponseSize"]读取。

内容的提问来源于stack exchange,提问作者ABHIJEET SINGH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:10:29