.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,直接配置即可:
- 在
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; });
- 启用响应压缩中间件(放在
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
相关产品推荐
相关产品推荐

