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

.NET 8响应压缩迁移问题:HttpResponse无Filter属性报错

问题

将应用从.NET Framework 4.8升级到.NET 8时,在实现输出压缩过滤器时遇到问题。

原.NET Framework 4.8实现代码:

public class CompressAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var encodingsAccepted = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(encodingsAccepted))
            return;
    
        encodingsAccepted = encodingsAccepted.ToUpperInvariant();
        var response = filterContext.HttpContext.Response;
    
        if (encodingsAccepted.Contains("DEFLATE"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionLevel.Fastest);
    
        }
        else if (encodingsAccepted.Contains("GZIP"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
    }
}

修改后的.NET 8代码:

public class CompressAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var encodingsAccepted = filterContext.HttpContext.Request.Headers.AcceptEncoding.FirstOrDefault()?.ToString();
        if (string.IsNullOrEmpty(encodingsAccepted))
            return;

        encodingsAccepted = encodingsAccepted.ToUpperInvariant();
        var response = filterContext.HttpContext.Response;

        if (encodingsAccepted.Contains("DEFLATE"))
        {
            response.Headers.ContentEncoding = "deflate";
            response.Filter = new DeflateStream(response.Filter, CompressionLevel.Fastest);

        }
        else if (encodingsAccepted.Contains("GZIP"))
        {
            response.Headers.ContentEncoding = "gzip";
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
    }
}

报错信息:HttpResponse不包含Filter属性的定义,需实现与原代码相同的功能。

解决方案

方式一:使用.NET 8内置响应压缩中间件(推荐)

ASP.NET Core(含.NET 8)已内置响应压缩功能,无需手动实现Filter,直接配置即可:

  1. 在Program.cs中添加响应压缩服务:
builder.Services.AddResponseCompression(options =>
{
    options.Providers.Add<GzipCompressionProvider>();
    options.Providers.Add<DeflateCompressionProvider>();
    options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/json" });
});

// 配置压缩级别
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.Fastest;
});

builder.Services.Configure<DeflateCompressionProviderOptions>(options =>
{
    options.Level = CompressionLevel.Fastest;
});
  1. 启用响应压缩中间件(放在app.UseRouting()之后,app.UseEndpoints()之前):
app.UseResponseCompression();

该方式会自动根据请求的Accept-Encoding头选择对应压缩方式,与原代码功能一致,且为官方推荐实现。

方式二:自定义ActionFilter实现(替代原Filter逻辑)

若需保持ActionFilter形式,可通过包装IActionResult实现压缩:

public class CompressAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        var encodingsAccepted = context.HttpContext.Request.Headers.AcceptEncoding.FirstOrDefault()?.ToString();
        if (string.IsNullOrEmpty(encodingsAccepted))
            return;

        encodingsAccepted = encodingsAccepted.ToUpperInvariant();
        var response = context.HttpContext.Response;

        if (context.Result is ObjectResult objectResult)
        {
            if (encodingsAccepted.Contains("DEFLATE"))
            {
                response.Headers.ContentEncoding = "deflate";
                context.Result = new CompressedObjectResult(objectResult.Value, CompressionType.Deflate);
            }
            else if (encodingsAccepted.Contains("GZIP"))
            {
                response.Headers.ContentEncoding = "gzip";
                context.Result = new CompressedObjectResult(objectResult.Value, CompressionType.Gzip);
            }
        }
    }

    private class CompressedObjectResult : ObjectResult
    {
        private readonly CompressionType _compressionType;

        public CompressedObjectResult(object value, CompressionType compressionType) : base(value)
        {
            _compressionType = compressionType;
        }

        public override async Task ExecuteResultAsync(ActionContext context)
        {
            var response = context.HttpContext.Response;
            await using var memoryStream = new MemoryStream();
            
            // 先将对象序列化到内存流
            await base.ExecuteResultAsync(new ActionContext(context.HttpContext, context.RouteData, context.ActionDescriptor)
            {
                Result = new ObjectResult(Value) { Formatters = Formatters }
            });
            
            // 重置内存流位置
            memoryStream.Position = 0;
            
            // 应用压缩
            response.ContentLength = null; // 压缩后长度变化,清除原长度
            if (_compressionType == CompressionType.Gzip)
            {
                await using var gzipStream = new GZipStream(response.Body, CompressionLevel.Fastest);
                await memoryStream.CopyToAsync(gzipStream);
            }
            else if (_compressionType == CompressionType.Deflate)
            {
                await using var deflateStream = new DeflateStream(response.Body, CompressionLevel.Fastest);
                await memoryStream.CopyToAsync(deflateStream);
            }
        }
    }

    private enum CompressionType
    {
        Gzip,
        Deflate
    }
}

说明:

  • 改用OnResultExecuting方法,在结果执行前替换为自定义压缩结果
  • 通过MemoryStream先序列化对象,再通过压缩流写入响应体
  • 该方式仅针对ObjectResult(如API返回的JSON结果),若需支持其他类型结果,可扩展对应处理逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 18:35:39