我正在将ASP.NET MVC 5应用程序迁移到ASP.NET Core 2.1。在" old"应用程序我有一个压缩过滤器,它将Gzip应用于特定请求的响应。这样我就能够仅压缩特定请求而不是所有请求。
根据我的理解,ASP.NET Core使用中间件有不同的方法,它只是让你有机会对所有请求(将其添加到管道)应用压缩或根本不应用它。
有没有办法通过创建ActionFilterAttribute来实现我想要的?这是我的旧代码:
public class CompressAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var acceptEncoding = filterContext.HttpContext.Request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(acceptEncoding))
return;
acceptEncoding = acceptEncoding.ToLower();
var response = filterContext.HttpContext.Response;
if (acceptEncoding.Contains("gzip"))
{
response.AppendHeader("Content-Encoding", "gzip");
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
else if (acceptEncoding.Contains("deflate"))
{
response.AppendHeader("Content-Encoding", "deflate");
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
}
}
答案 0 :(得分:1)
我发现了两种将压缩应用于特定情况的方法:
1)创建中间件并在应用压缩之前分析请求。我不喜欢这种方法,因为中间件将针对所有请求运行,并且必须检查请求信息,从而影响性能。
2)修改Web.config文件(这是我采用的方法),并将压缩应用于某些动态和静态类型。发布ASP.NET Core应用后,会自动生成一个web.config。我们可以像下面的示例一样编辑web.config文件并添加压缩:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<urlCompression doStaticCompression="true" doDynamicCompression="true" />
<httpCompression>
<dynamicTypes>
<clear />
<add enabled="true" mimeType="text/*" />
<add enabled="true" mimeType="message/*" />
<add enabled="true" mimeType="application/x-javascript" />
<add enabled="true" mimeType="application/javascript" />
<add enabled="true" mimeType="application/json" />
<add enabled="false" mimeType="*/*" />
<add enabled="true" mimeType="application/atom+xml" />
<add enabled="true" mimeType="application/atom+xml;charset=utf-8" />
</dynamicTypes>
<staticTypes>
<clear />
<add enabled="true" mimeType="text/*" />
<add enabled="true" mimeType="message/*" />
<add enabled="true" mimeType="application/javascript" />
<add enabled="true" mimeType="application/atom+xml" />
<add enabled="true" mimeType="application/xaml+xml" />
<add enabled="false" mimeType="*/*" />
</staticTypes>
</httpCompression>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\YourApplicationName.dll" stdoutLogEnabled="false" stdoutLogFile="\\?\%home%\LogFiles\stdout" />
</system.webServer>
</configuration>
答案 1 :(得分:0)
我还有一个任务是仅压缩某些特定操作/控制器的响应
最后,我找到了基于ActionFilterAttribute
的解决方案。这是一个例子
namespace CommonWebApi.MiddleWare
{
/// <summary>
/// Attribute for enabling Brotli/GZip/Deflate compression for specied action
/// </summary>
public class ResponseCompressionAttribute : ActionFilterAttribute
{
private Stream _originStream = null;
private MemoryStream _ms = null;
public override void OnActionExecuting(ActionExecutingContext context)
{
HttpRequest request = context.HttpContext.Request;
string acceptEncoding = request.Headers["Accept-Encoding"];
if (string.IsNullOrEmpty(acceptEncoding)) return;
acceptEncoding = acceptEncoding.ToUpperInvariant();
HttpResponse response = context.HttpContext.Response;
if (acceptEncoding.Contains("BR", StringComparison.OrdinalIgnoreCase))//Brotli
{
if (!(response.Body is BrotliStream))// avoid twice compression.
{
_originStream = response.Body;
_ms = new MemoryStream();
response.Headers.Add("Content-encoding", "br");
response.Body = new BrotliStream(_ms, CompressionLevel.Optimal);
}
}
else if (acceptEncoding.Contains("GZIP", StringComparison.OrdinalIgnoreCase))
{
if (!(response.Body is GZipStream))
{
_originStream = response.Body;
_ms = new MemoryStream();
response.Headers.Add("Content-Encoding", "gzip");
response.Body = new GZipStream(_ms, CompressionLevel.Optimal);
}
}
else if (acceptEncoding.Contains("DEFLATE", StringComparison.OrdinalIgnoreCase))
{
if (!(response.Body is DeflateStream))
{
_originStream = response.Body;
_ms = new MemoryStream();
response.Headers.Add("Content-encoding", "deflate");
response.Body = new DeflateStream(_ms, CompressionLevel.Optimal);
}
}
base.OnActionExecuting(context);
}
public override async void OnResultExecuted(ResultExecutedContext context)
{
if ((_originStream != null) && (_ms != null))
{
HttpResponse response = context.HttpContext.Response;
await response.Body.FlushAsync();
_ms.Seek(0, SeekOrigin.Begin);
response.Headers.ContentLength = _ms.Length;
await _ms.CopyToAsync(_originStream);
response.Body.Dispose();
_ms.Dispose();
response.Body = _originStream;
}
base.OnResultExecuted(context);
}
}
}
已知限制/要点:
response.Headers.ContentLength
。