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

如何在.NET 5的Action Filter中手动实现HttpResponse的GZip压缩

实现方案

ASP.NET Core 中 MVC Filter 的响应流处理逻辑和 .NET Framework 不同,不能直接替换响应流实现压缩,需要先暂存 Action 生成的全部响应内容,再压缩写入原始响应流,完整实现如下:

using System.IO.Compression;
using Microsoft.AspNetCore.Mvc.Filters;

public class GzipCompressionFilter : IAsyncActionFilter
{
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var httpContext = context.HttpContext;
        var response = httpContext.Response;

        // 校验客户端是否支持gzip压缩
        var acceptEncoding = httpContext.Request.Headers.AcceptEncoding.ToString();
        if (!acceptEncoding.Contains("gzip", StringComparison.OrdinalIgnoreCase))
        {
            await next();
            return;
        }

        // 保存原始响应流
        var originalBodyStream = response.Body;
        // 用内存流暂存未压缩的响应内容
        using var memoryStream = new MemoryStream();
        response.Body = memoryStream;

        // 执行Action逻辑生成响应内容
        var executedContext = await next();

        // 仅请求成功时执行压缩
        if (executedContext.Exception == null && response.StatusCode == StatusCodes.Status200OK)
        {
            memoryStream.Seek(0, SeekOrigin.Begin);
            // 添加压缩标识头
            response.Headers.ContentEncoding = "gzip";
            // 移除原Content-Length头,压缩后内容长度已变化
            response.Headers.Remove("Content-Length");

            // 压缩内容写入原始响应流
            using var gzipStream = new GZipStream(originalBodyStream, CompressionMode.Compress, leaveOpen: true);
            await memoryStream.CopyToAsync(gzipStream);
        }
        else
        {
            // 异常/非成功响应直接返回原内容
            memoryStream.Seek(0, SeekOrigin.Begin);
            await memoryStream.CopyToAsync(originalBodyStream);
        }

        // 恢复原始响应流,避免后续框架逻辑报错
        response.Body = originalBodyStream;
    }
}

注册方式

如果需要全局生效,在Program.cs中添加配置:

builder.Services.AddControllers(options =>
{
    options.Filters.Add<GzipCompressionFilter>();
});

如果仅需要给指定Controller/Action生效,给对应类/方法添加特性即可:

[TypeFilter(typeof(GzipCompressionFilter))]
public class TestController : ControllerBase
{
    // Action逻辑
}

注意事项

  • 不要使用async void实现Filter方法,会导致异步操作未完成就释放资源,引发流异常
  • GZipStream的leaveOpen参数要设为true,避免压缩流释放时把框架管理的原始响应流关闭
  • 非200状态码或者请求异常时不要执行压缩,避免错误信息无法正常解析

内容的提问来源于stack exchange,提问作者Katie P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 12:36:06