Web API Gzip not being applied

2019-03-12 09:24发布

问题:

I have added the web.config entry to enable gzip compression based on this S/O answer Enable IIS7 gzip.

I then checked the Chrome Developer window while loading an ASPX page and saw the header in the response:

Cache-Control:private
Content-Encoding:gzip
Content-Length:3669
Content-Type:text/html; charset=utf-8
Date:Wed, 04 Mar 2015 00:46:05 GMT
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

So that means it's "working", correct? But when looking for that header when making a Web API call, it is not present:

Cache-Control:no-cache
Content-Length:551
Content-Type:application/json; charset=utf-8
Date:Wed, 04 Mar 2015 00:53:05 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET

I have tried all kinds of different configurations (starting with the one recommended in the linked S/O answer above). Finally, in an act of desperation, I set it to this, which I thought would make it try to compress all requests (everything except */* commented out):

  <httpCompression directory="%SystemDrive%\inetpub\temp\IIS Temporary Compressed Files">
    <scheme name="gzip" dll="%Windir%\system32\inetsrv\gzip.dll"/>
    <dynamicTypes>
      <add mimeType="*/*" enabled="true"/>
      <!--<add mimeType="text/*" enabled="true"/>
      <add mimeType="message/*" enabled="true"/>
      <add mimeType="application/javascript" enabled="true"/>
      <add mimeType="application/json" enabled="true"/>-->
      <!--<add mimeType="*/*" enabled="false"/> -->
    </dynamicTypes>
    <staticTypes>
      <add mimeType="*/*" enabled="true"/>
      <!--<add mimeType="text/*" enabled="true"/>
      <add mimeType="message/*" enabled="true"/>
      <add mimeType="application/javascript" enabled="true"/>
      <add mimeType="application/json" enabled="true"/>-->
      <!-- add mimeType="*/*" enabled="false"/>-->
    </staticTypes>
  </httpCompression>
  <urlCompression doStaticCompression="true" doDynamicCompression="true"/>

What can be preventing the GZIP from being applied to my Web API methods?

Update

I have since tried both the NuGet Web API Compression package, and editing the applicationHost.config in both IIS Express 8.0 (Visual Studio) and a locally-installed IIS 7.5. All have yielded the same results: requests for other mime types like text/* work, but application/json refuses to be gzipped.

回答1:

Is the WebAPI behind a Firewall, Web Proxy, Virus Protection Suite? As mentioned in Even Faster Web Sites: Performance Best Practices for Web Developers By Steve Souders This could be stripping out the headers.



回答2:

According to ASP.NET Web API Compression (Ben Foster Blog) you have two options:

  1. Change your applicationHost.config and add

    to httpCompression -> dynamicTypes section.

  2. Use an delegating handler in your web api pipeline to handle the compression.
    e.g. Fabrik.Common or Microsoft ASP.NET Web API Compression Support



回答3:

Thanks to the 2 above solutions and other solutions elsewhere I figured a step by step explanation of how to get http compression working with Web API 2.2 might be beneficial as a few packages/namespaces have changed since the above posts.

1) Using nuget package manager console install the following;

Install-Package Microsoft.AspNet.WebApi.MessageHandlers.Compression

2) Inside WebApiConfig.cs add these usings;

using System.Net.Http.Extensions.Compression.Core.Compressors;
using Microsoft.AspNet.WebApi.Extensions.Compression.Server;

3) Inside WebApiConfig.cs add to the bottom of Register(HttpConfiguration config);

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

4) Edit your web.config and inside system.webServer add;

<urlCompression doStaticCompression="true" doDynamicCompression="true" dynamicCompressionBeforeCache="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" />
    </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="true" mimeType="application/json" />
        <add enabled="false" mimeType="*/*" />
    </staticTypes>
</httpCompression>

Worked first time on both local and an azure website so hopefully it works for you! Plus certainly no need to mess with applicationHost.config...



回答4:

I think you have made all the homework in the server side, but the problem is in the request.

To allow the server to compress the response it's neccessary to inclue this header in the request:

Accept-Encoding: gzip, deflate

If you don't do it, no matter what you do on the server side, the response will never be compressed.

You don't specify which is your Web API client, but there is always a way to add headers in the request using the client API.



回答5:

I think @Peeticus was on the right track.

Here is what I did to make it work:

After running "Install-Package Microsoft.AspNet.WebApi.MessageHandlers.Compression" or adding it thru the GUI you need to update /App_Start/WebApiConfig.cs

The following additional using statements are required:

using Microsoft.AspNet.WebApi.MessageHandlers.Compression.Compressors;
using Microsoft.AspNet.WebApi.MessageHandlers.Compression;

Add the following inside the WebApiConfig.Register method:

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

Next in the IISExpress applicationHost.config find the <httpCompression>'s <dynamicTypes> element and the following before the default <add mimeType="/" enabled="false" />

<add mimeType="application/json" enabled="true" />

Also in the applicationHost.config update <urlCompression /> to

<urlCompression doDynamicCompression="true" />


回答6:

In your implementation of the NuGet package Microsoft.AspNet.WebApi.MessageHandlers.Compression, did you add the requisite line (below) to your App_Start\WebApiConfig.cs file? Note that is must be after all other message handlers in that same method, as per instructions on the package's home site.

GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));

Here's a sample Register method from a WebApiConfig file that I used in a blog:

    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { echo = RouteParameter.Optional }
        );
        GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
    }

This is the blog post I mentioned: .Net Web API Compression



回答7:

At first.

IIS Ignores WEB API Response compression because web api responses are of mime type

application/json; charset=utf-8

Default IIS Compression settings do not include this Mime type so they do not compress the response.

So your have to add this mime type to the <dynamicTypes> section

<add mimeType="application/json; charset=utf-8" enabled="true" />

(Or just to test it , as you did <add mimeType="*/*" enabled="true" />)

BUT

By default <httpCompression> Section is locked by IIS for settings from outside!!

So any settings you specify on your web.config will get ignored!

Unless you specify these settings on the applicationHost.config <httpCompression> section OR edit the <httpCompression> section to allow settingsfrom outside.

<section name="httpCompression" allowDefinition="MachineToApplication" overrideModeDefault="Allow" />