如何在ASP.NET MVC中压缩内容?

42

如何压缩由ASP.NET MVC应用程序发送的输出?


为什么不在web.config中设置<urlCompression doDynamicCompression="true" />或者甚至<urlCompression doStaticCompression="true" doDynamicCompression="true" />呢?你可以参考这个链接:http://www.iis.net/configreference/system.webserver/httpcompression,以及这个问题的解答:https://dev59.com/lWDVa4cB1Zd3GeqPcE01。 - angularrocks.com
您还可以通过使用响应数据的压缩和缓存来提高性能。请查看以下链接:http://weblogs.asp.net/rashid/asp-net-mvc-action-filter-caching-and-compression - Aishwarya Nagar
3个回答

94

以下是我目前使用的内容:

using  System.IO.Compression;

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.ToLowerInvariant();
        var response = filterContext.HttpContext.Response;

        if (encodingsAccepted.Contains("deflate"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
        else if (encodingsAccepted.Contains("gzip"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
    }
}

在控制器中的用法:

[Compress]
public class BookingController : BaseController
{...}

还有其它的变体,但这个方法运行得很好。(顺便提一下,我在我的BaseController上使用[Compress]属性来避免项目中的重复,而上面的方法则是对每个控制器逐个处理。)

[编辑] 如前面所述,为了简化使用,你也可以在BaseController本身中包含[Compress] oneshot,因此,每个继承的子控制器默认地访问该功能:

[Compress]
public class BaseController : Controller
{...}

为什么不直接使用IIS的urlCompression?https://dev59.com/lWDVa4cB1Zd3GeqPcE01?lq=1 - angularrocks.com
9
我将其添加为全局过滤器,在我的启动类中添加了 GlobalFilter.Filters.Add(new CompressionAttribute());,它可以正常工作 #1!同时颠倒了 if 语句的顺序,以确保当支持两种编码方式时使用 gzip 而不是 deflate - Charles Ouellet
2
只是想补充一下,如果你没有从基本控制器派生开始,不要害怕。你总是可以使用一个IoC容器来处理它。例如,在Ninject(MVC 5)中,您可以在“RegisterServices(IKernel kernel)”方法下使用:“kernel.BindFilter <CompressAttribute>(FilterScope.Controller,0);”! - Jose A
1
很棒的回答。但是为什么你把 deflate 选项放在第一位,我改变了顺序,现在把 gzip 放在第一位,压缩率提高了约10%。 - Juan Carlos Oropeza
1
重要提示!在将其放入流之前,应检查response.Filter是否为null!我遇到了问题,当本地一切正常时,但部署到Azure服务时失败。 - Yehor Androsov
显示剩余11条评论

4
请看this article,其中介绍了一种巧妙利用Action Filters的方法。
例如:
[CompressFilter]
public void Category(string name, int? page)

作为额外的奖励,它还包括一个CacheFilter。

好的,正在测试这个,还有一件事我想知道,我怎么检查从服务器获取的数据是否经过gzip压缩? - Praveen Prasad
使用文章中提到的Firebug,并查看响应头。 - veggerby
1
无法在MVC5、IIS 8.5和.Net 4.5上工作,任何帮助将不胜感激。 - aadi1295

3

对于.NET Core 2.1,有一个新的包可以使用(Microsoft.AspNetCore.ResponseCompression)。

以下是一个简单的示例,安装了该包后即可运行:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();

        services.AddResponseCompression(options =>
        {
            options.Providers.Add<GzipCompressionProvider>();
            options.EnableForHttps = true;
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

你可以在这里阅读更多相关信息:https://learn.microsoft.com/en-us/aspnet/core/performance/response-compression?view=aspnetcore-2.1&tabs=aspnetcore2x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接