在IIS7上托管WCF时使用GZip压缩

24

我认为,对于这个问题,我的回答在第二次编辑中得到了解答。虽然它只是该问题在IIS方面的部分解决方案,但这正是我所期望的。


因此,我将把我的疑问添加到关于这个主题的众多问题之中。

我正在尝试启用WCF服务中大型SOAP响应的GZip压缩。到目前为止,我已经按照这里和其他地方的各种指示启用了IIS上的动态压缩。下面是来自applicationHost.config的dynamicTypes部分:

<dynamicTypes>
    <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/xop+xml" enabled="true" />
    <add mimeType="application/soap+xml" enabled="true" />
    <add mimeType="*/*" enabled="false" />
</dynamicTypes>

还有:

<urlCompression doDynamicCompression="true" doStaticCompression="true" />

虽然我不是很清楚为什么需要这样做。

为了保险起见,我在那里添加了一些额外的MIME类型。我实现了IClientMessageInspector接口,以向客户端的Http请求添加Accept-Encoding:gzip、deflate。以下是从fiddler中获取的请求头示例:

POST http://[omitted]/TestMtomService/TextService.svc HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Accept-Encoding: gzip, deflate
Host: [omitted]
Content-Length: 542
Expect: 100-continue
现在,这并不起作用。无论消息的大小如何(已尝试了高达1.5Mb),都没有进行压缩。我看过这篇帖子,但没有遇到他所描述的异常,因此我没有尝试他提出的CodeProject实现。而且我看到了很多其他的实现,它们应该可以让这个工作,但是无法理解它们(例如,msdn的GZip编码器)。为什么我需要实现编码器或代码项目解决方案?难道IIS不能处理压缩吗?
那么,我还需要做什么才能让它起作用呢?
Joni
编辑: 我认为WCF绑定可能值得发布,尽管我不确定它们是否相关(这些来自客户端):
<system.serviceModel>
<bindings>
    <wsHttpBinding>
    <binding name="WsTextBinding" closeTimeout="00:01:00" openTimeout="00:01:00"
      receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false"
      transactionFlow="false" hostNameComparisonMode="StrongWildcard"
      maxBufferPoolSize="5000000" maxReceivedMessageSize="5000000"
      messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
      allowCookies="false">
      <readerQuotas maxDepth="32" maxStringContentLength="5000000"
        maxArrayLength="5000000" maxBytesPerRead="5000000" maxNameTableCharCount="5000000" />
      <reliableSession ordered="true" inactivityTimeout="00:10:00"
        enabled="false" />
      <security mode="None">
        <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
        <message clientCredentialType="None" negotiateServiceCredential="false"
          algorithmSuite="Default" establishSecurityContext="false" />
      </security>
<client>
  <endpoint address="http://[omitted]/TestMtomService/TextService.svc"
   binding="wsHttpBinding" bindingConfiguration="WsTextBinding" behaviorConfiguration="GzipCompressionBehavior"
   contract="TestMtomModel.ICustomerService" name="WsTextEndpoint">
  </endpoint>
</client>
<behaviors>
  <endpointBehaviors>
    <behavior name="GzipCompressionBehavior">
      <gzipCompression />
    </behavior>
  </endpointBehaviors>
</behaviors>
<extensions>
  <behaviorExtensions>
    <add name="gzipCompression"
         type="TestMtomModel.Behavior.GzipCompressionBehaviorExtensionElement, TestMtomModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
    </binding>
  </wsHttpBinding>
</bindings>

编辑2: 对于其他处于这种神秘情况中的人,我有一个部分解决方案。也就是说,我已经让IIS7至少压缩了来自服务的soap消息(虽然现在客户端出现了异常,但已经有几个解决方案发布)。 问题在于我的服务器上没有安装DynamicCompressionModule。对于我来说,“安装”它实际上意味着将以下行添加到applicationHost.config的“section”中:

<add name="DynamicCompressionModule" image="%windir%\System32\inetsrv\compdyn.dll" />

(假设dll文件存在于该目录中,在我的情况下它确实存在。) 然后通过IIS7的网站或服务器的模块部分添加该模块。


可能是一个愚蠢的问题,但它困扰了我一段时间 - 你怎么知道压缩没有发生?如果原因是你在 Fiddler 中没有看到它,要知道 Fiddler 会自动解压,除非你告诉它不要这样做。 - Marc Bernier
8个回答

14

尝试在applicationHost中添加“application/soap+xml; charset=utf-8”作为动态类型。添加此字符集部分可以帮助我启用我的HTTP处理程序中某些JSON响应的压缩。


1
+1 - 这就是答案 - 我必须完全按照这样的方式来使压缩工作,而不使用任何额外的组件。也就是说,假设动态压缩模块已经开启并安装好了 :) - Andras Zoltan
1
您可能需要多次启用相同的MIME类型,因为Microsoft倾向于进行字符串比较而不是内容比较。(即application/soap+xml;charset=utf-8application/soap+xml;charset=ISO-8895-1application/soap+xml; charset=ISO-8895-1) - jrista
在IIS7中为WCF数据源、OData和其他自定义服务启用动态压缩(gzip、deflate)--- http://www.hanselman.com/blog/EnablingDynamicCompressionGzipDeflateForWCFDataFeedsODataAndOtherCustomServicesInIIS7.aspx - hB0

10

这基本上是与@marko相同的答案 - 并附有详细步骤。每次我重新访问它时,这都是一个令人沮丧的话题,因此我想概述我需要做的一切才能使其正常工作。

  • 首先,您需要在IIS7上使用.NET 4。这是因为直到.NET 4,WCF才能自动解压缩gzip流。关于此的详细信息可以在“WCF 4中的新功能”(反馈中有一些有用的评论)中找到。

    我们通过允许客户端自动协商使用gzip或deflate压缩流,然后自动解压缩它们来使HTTP使用更加容易。

  • 其次,请确保已在IIS中启用了动态压缩模块。您可能需要转到“程序和功能”进行安装。请确保为涉及的Web应用程序启用了该模块,因为它不是全局设置。

  • 现在,WPF使用MIME类型application/soap+xml; charset=utf-8进行HTTP传输(至少使用wsHttpBinding)。 默认情况下,此类型不被视为动态类型,因此需要将其添加到applicationHost.config文件中。

    只需编辑服务器上的此文件:C:\Windows\System32\Inetsrv\Config\applicationHost.config

    <dynamicTypes>节点中添加以下行(在/行之前):

    <add mimeType="application/soap+xml; charset=utf-8" enabled="true" />
    

    关于 applicationHost.config 文件的更多信息

  • 重新启动 IIS

现在应该有压缩数据了 - 可以在 Fiddler 中进行验证。


1
这篇文章真是精华啊!非常感谢!(真是太神奇了,对的文章能让你找到答案,而其他的只会让你更加困惑!) - Jonesome Reinstate Monica
2
抱歉问一个愚蠢的问题,为什么不能在应用程序的web.config中设置mimeType?我已经尝试过了,但不起作用。但是为什么呢?对我来说,编辑托管我的应用程序的每个单独服务器上的applicationhost.config不太合适。 - Karel Kral

1

我也一直在努力解决这个问题,即使在同一个应用程序中的.aspx文件中没有问题,但我无法让它与我的.svc文件一起正常工作。事实证明,它只适用于basicHttpBinding而不是wsHttpBinding或二进制编码的customBinding。对我来说,这很好,因为压缩因素超过了二进制编码器的好处(它可以将消息大小减小很多,但不是压缩所给出的10倍)。


请查看我的答案,了解为什么它适用于basicHttpBinding而不适用于wsHttpBinding。有一种方法! - e36M3

0
只是为了那些将来可能会看到的其他人。我们升级到了Windows 2012服务器和IIS 8。旧的配置压缩mimetype在IIS 7上工作,但在IIS 8上无效。
所以,我试了一些建议,但都没有起作用。最后,我只是在httpcompression dynamictypes中添加了multipart/*,然后gzip压缩又开始工作了。
希望这对其他人有所帮助。

0

该 MIME 类型很可能是 Application/octet-stream


0

最好的方法是评估您遇到问题的特定 MIME 类型(例如 Fiddler),并确保将其纳入 applicationHost.config。如果压缩已安装并正确配置,则失败的请求跟踪将告诉您,压缩未执行,并显示“NO_MATCHING_CONTENT_TYPE”状态。


谢谢大家的回答。然而,IIS方面的问题已经解决了,请阅读原帖中的“编辑2”。如果可以的话,我会将这个问题标记为答案,即使它只是这个问题的部分解决方案,但我不能这样做。 - joniba

0
很多人在启用WCF服务的IIS级压缩方面遇到了困难。主要是人们在使用wsHttpBinding时遇到了困难,而如果启用了IIS中的动态压缩,则basicHttpBinding可以直接进行压缩。我不会详细介绍如何启用动态压缩,因为这已经在许多不同的帖子中涵盖了,只需搜索“iis compression application/soap+xml”即可。正如先前所述,如果您正确配置了所有内容,您应该能够看到WCF响应以“Content-Encoding: gzip”压缩在响应头中。建议使用Fiddler跟踪您的请求/响应。这是我(和许多其他人)使用basicHttpBinding的经验。那么问题就是为什么wsHttpBinding不能正常工作?毫无疑问,您已经读到了这两个绑定之间的“Content-Type”不同的原因。basicHttpBinding使用“Content-Type: text/xml; charset=utf-8”,而wsHttpBinding使用“Content-Type: application/soap+xml; charset=utf-8”。前者由默认的IIS applicationHost.config设置下的dynamicTypes覆盖。后者则没有。您可能已经读到需要添加此附加mimeType并重新启动IIS才能解决此问题。这对某些人有效,但对许多人无效。有些人宣称它与wsHttpBinding根本不兼容。这就是问题所在。可能有两个applicationHost.config文件:
C:\Windows\System32\inetsrv\config
C:\Windows\SysWOW64\inetsrv\Config

System32是64位的,也是您安装IIS时使用的一个。这也是您修改添加额外mimeType的文件,或者您认为是这样!

无法手动编辑applicationhost.config - 必读

事实证明,如果您使用像Notepad++这样的32位应用程序,您最终修改的是SysWOW64文件夹中的文件。这对您来说是完全透明的。如果您使用常规的记事本应用程序,您会注意到您添加的mimeType实际上不在位于System32文件夹中的文件中,它神奇地添加到了SysWOW64文件夹中,即使您从未实际浏览过该文件夹。希望这能为您节省许多时间和烦恼。


0
如果有人在 Azure 上托管 WebApp 时遇到问题,可以使用名为“ IIS 管理器”的扩展程序,在 Azure 门户下的“扩展”中配置 applicationHost.config。关于该扩展本身的更多信息,请参见 https://github.com/shibayan/IISManager

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