如何在ASP.NET MVC中使用IIS 7.5压缩Json结果

57

我在尝试让ASP.NET MVC返回的Json结果在IIS 7上正确压缩时遇到了困难。我已经在IIS中启用了静态和动态压缩。我可以通过Fiddler验证普通的文本/HTML和类似的记录已被压缩。查看请求时,accept-encoding gzip头已存在。响应具有Mimetype“application/json”,但未被压缩。

我已确定问题似乎与MimeType有关。当我包括mimeType="*/*"时,我可以看到响应已被正确地压缩。如何在不使用通配符MimeType的情况下让IIS进行压缩?我认为这个问题与ASP.NET MVC生成内容类型标头的方式有关。

CPU使用率远低于动态调节阈值。当我检查来自IIS的跟踪日志时,我发现它无法压缩因为未找到匹配的MimeType。

<httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files" noCompressionForProxies="false">
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll" />
    <dynamicTypes>
        <add mimeType="text/*" enabled="true" />
        <add mimeType="message/*" enabled="true" />
        <add mimeType="application/x-javascript" enabled="true" />
        <add mimeType="application/json" enabled="true" />
    </dynamicTypes>
    <staticTypes>
        <add mimeType="text/*" enabled="true" />
        <add mimeType="message/*" enabled="true" />
        <add mimeType="application/x-javascript" enabled="true" />
        <add mimeType="application/atom+xml" enabled="true" />
        <add mimeType="application/xaml+xml" enabled="true" />
        <add mimeType="application/json" enabled="true" />
    </staticTypes>
</httpCompression>

1
我无法使用通配符MIME类型,因为我在IE8遇到了一个奇怪的问题——当请求被IIS进一步压缩时,它似乎难以下载.zip文件。Firefox 3.5不受影响。 - Gareth Saul
5个回答

62

请确保您的%WinDir%\System32\inetsrv\config\applicationHost.config文件包含以下内容:

<system.webServer>
    <urlCompression doDynamicCompression="true" />
    <httpCompression>
      <dynamicTypes>
        <add mimeType="application/json" enabled="true" />
        <add mimeType="application/json; charset=utf-8" enabled="true" />       
      </dynamicTypes>
    </httpCompression>
</system.webServer>

从@AtanasKorchev的链接中获取。

正如@simon_weaver在评论中所说,您可能正在使用32位编辑器编辑64位Windows上的错误文件,请使用notepad.exe确保该文件确实被修改。


2
注意:如果出现“applicationHost.config”似乎丢失的情况,您可能正在使用32位编辑器的64位机器上。当然,在备份之后尝试使用记事本。http://www.west-wind.com/weblog/posts/2008/Aug/09/Editing-Applicationhostconfig-on-64-bit-Win2008 - Simon_Weaver
小时啊,我花了好几个小时试图发现为什么我的gzipped application/json没有从我的IIS中出来...这最终起作用了!谢谢! - Aviad P.
不要忘记对应用程序池进行回收。 - Mr_LinDowsMac

22

10
我之前看过那篇文章,但认为它没有增加任何新的或有用的东西。看来与其他MIME类型不同,你需要在IIS 7中指定内容编码才能压缩来自ASP.NET MVC的application/json响应。仅仅说“application/json”是不够的,还需要是“application/json; charset=utf-8”。 - Gareth Saul
注意:如果 applicationHost.config 文件似乎丢失了,你可能在使用 32 位编辑器的 64 位机器上。当然,在备份后尝试使用记事本进行编辑。http://www.west-wind.com/weblog/posts/2008/Aug/09/Editing-Applicationhostconfig-on-64-bit-Win2008 - Simon_Weaver

14

使用此指南

对我来说,这些答案都不起作用。不过,我注意到了application/json; charset=utf-8的 MIME 类型。


1
+1:对于我来说这有效,使用 application/json; charset=utf-8 媒体类型。:o) - Andrew
这对我有效,但你需要记得重新启动服务器而不仅仅是网站。即在启动inetmgr后,单击服务器名称并直接转到“管理服务器”部分 - 使用该重启选项而不是单个网站的重启。 - wal

7

我推荐使用这种方法
创建CompressAttribute类,并设置目标操作。


1
只有当其他所有方法都失败了,IIS7+ 才能做得更好吗? - Alex Nolasco
1
这是一个不错的解决方案,因为你可以缓存和压缩,而IIS只能缓存或压缩。 - David Hayes
1
这也是一种不错的方法,因为压缩小消息可能会在压缩/解压缩方面花费比纯传输数据更多的成本。在应用程序中为所有JSON下载设置gzip实际上可能会为这些较小的消息耗费时间,因此仅装饰大型下载具有其优点。 - Jason Jackson
更新了到archive.org的链接。 - MatthewMartin

2

针对ASP.NET 4.x更新的ActionFilterAttribute方法,并包含Brotli.NET软件包。

using System;
using System.IO.Compression;
using Brotli;
using System.Web;
using System.Web.Mvc;


public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        string acceptEncoding = request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(acceptEncoding)) return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();
        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("BR"))
        {
            response.AppendHeader("Content-encoding", "br");
            response.Filter = new BrotliStream(response.Filter, CompressionMode.Compress);
        }
        else 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);
        }
    }
}

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