我有一个WebAPI控制器,返回HttpResponseMessage,我想添加gzip压缩.这是服务器代码:

using System.Net.Http;
using System.Web.Http;
using System.Web;
using System.IO.Compression;

[Route("SomeRoute")]
public HttpResponseMessage Post([FromBody] string value)
{
    HttpContext context = HttpContext.Current;

    context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);

    HttpContext.Current.Response.AppendHeader("Content-encoding", "gzip");
    HttpContext.Current.Response.Cache.VaryByHeaders["Accept-encoding"] = true;

    return new SomeClass().SomeRequest(value);
}

下面是Ajax调用的客户端代码,使用jQuery:

$.ajax({
    url: "/SomeRoute",
    type: "POST",
    cache: "false",
    data: SomeData,
    beforeSend: function (jqXHR) { jqXHR.setRequestHeader('Accept-Encoding', 'gzip'); },
    success: function(msg) { ... }

当我运行此程序时,服务器代码返回时没有出现错误,但客户端出现错误:

(failed)
net::ERR_CONTENT_DECODING_FAILED

在此处输入图像描述

当我和Fiddler一起看的时候,我看到的是:

在此处输入图像描述

我需要进行哪些更改才能使Web服务返回客户端正常处理的gzip内容?我知道我也可以使用HttpModule或通过IIS上的某些设置来实现这一点,但这两种 Select 都不适合托管的场景:

在此处输入图像描述

Please note that I'm not looking for an IIS setting because I don't have access to that (hosting).

推荐答案

If you have access to IIS configuration

你不能仅仅应用标题并希望它被压缩——响应不会被压缩.

您需要删除添加的头文件,并确保在IIS服务器上启用了动态压缩和静电内容压缩.

其中一位 comments 者在stakoverflow提到了一个很好的资源链接,展示了如何做到这一点:

Enable IIS7 gzip

注意,它只会在web中设置值.如果已安装动态压缩,请进行配置(这不是IIS的默认安装)

您可以在MSDN文档中找到相关信息:http://www.iis.net/configreference/system.webserver/httpcompression

Simple compression

下面是一个简单的压缩示例.这个示例使用visual studio项目模板中的Web Api MVC 4项目.要使HttpResponseMessages的压缩工作正常,必须实现自定义MessageHandler.参见下面的工作示例.

请参见下面的代码实现.

Please note that I tried to keep the method doing the same as your example.

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.Controllers
{
    public class ValuesController : ApiController
    {
        public class Person
        {
            public string name { get; set; }
        }
        // GET api/values
        public IEnumerable<string> Get()
        {
            HttpContext.Current.Response.Cache.VaryByHeaders["accept-encoding"] = true;

            return new [] { "value1", "value2" };
        }

        // GET api/values/5
        public HttpResponseMessage Get(int id)
        {
            HttpContext.Current.Response.Cache.VaryByHeaders["accept-encoding"] = true;

            var TheHTTPResponse = new HttpResponseMessage(System.Net.HttpStatusCode.OK); 
            TheHTTPResponse.Content = new StringContent("{\"asdasdasdsadsad\": 123123123 }", Encoding.UTF8, "text/json"); 

            return TheHTTPResponse;
        }

        public class EncodingDelegateHandler : DelegatingHandler
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
                {
                    HttpResponseMessage response = responseToCompleteTask.Result;

                    if (response.RequestMessage.Headers.AcceptEncoding != null &&
                        response.RequestMessage.Headers.AcceptEncoding.Count > 0)
                    {
                        string encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value;

                        response.Content = new CompressedContent(response.Content, encodingType);
                    }

                    return response;
                },
                TaskContinuationOptions.OnlyOnRanToCompletion);
            }
        }

        public class CompressedContent : HttpContent
        {
            private HttpContent originalContent;
            private string encodingType;

            public CompressedContent(HttpContent content, string encodingType)
            {
                if (content == null)
                {
                    throw new ArgumentNullException("content");
                }

                if (encodingType == null)
                {
                    throw new ArgumentNullException("encodingType");
                }

                originalContent = content;
                this.encodingType = encodingType.ToLowerInvariant();

                if (this.encodingType != "gzip" && this.encodingType != "deflate")
                {
                    throw new InvalidOperationException(string.Format("Encoding '{0}' is not supported. Only supports gzip or deflate encoding.", this.encodingType));
                }

                // copy the headers from the original content
                foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
                {
                    this.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }

                this.Headers.ContentEncoding.Add(encodingType);
            }

            protected override bool TryComputeLength(out long length)
            {
                length = -1;

                return false;
            }

            protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
            {
                Stream compressedStream = null;

                if (encodingType == "gzip")
                {
                    compressedStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true);
                }
                else if (encodingType == "deflate")
                {
                    compressedStream = new DeflateStream(stream, CompressionMode.Compress, leaveOpen: true);
                }

                return originalContent.CopyToAsync(compressedStream).ContinueWith(tsk =>
                {
                    if (compressedStream != null)
                    {
                        compressedStream.Dispose();
                    }
                });
            }
        }
    }
}

还可以将新的消息处理程序添加到应用程序的配置中.

using System.Web.Http;
using MvcApplication1.Controllers;

namespace MvcApplication1
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.MessageHandlers.Add(new ValuesController.EncodingDelegateHandler());

            config.EnableSystemDiagnosticsTracing();
        }
    }
}

定制处理程序由-Kiran Challa(http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx)组装而成

还有更好的示例来实现入站流的放气,您也可以看到下面的示例:

此外,我在github上发现了一个非常好的项目,支持所有这些.

注意:当我自己回答这个问题时,Simon在您的 comments 中建议从这个答案的日期起2天前使用这个方法.

Asp.net相关问答推荐

如何在 ASP.NET 中设置自动实现属性的默认值

系统日期时间?与 System.DateTime

ASP.NET web api 无法获取 application/x-www-form-urlencoded HTTP POST

如何使用 jQuery 设置 outerHTML

我应该使用用户名还是用户 ID 来引用 ASP.NET 中经过身份验证的用户

如何使用文件上传控件 Select 多个文件?

你如何确定哪个验证器失败了?

是否有用于 Asp.net 标记的#IF DEBUG?

温莎城堡有什么缺点吗?

使用 Moq 验证活动注册

IIS Express 安装目录在哪里?

捕获的异常本身为 null !

在 Visual Studio 2010 中随机禁用编辑 aspx/ascx 文件?

在后面的代码中删除 css 类

如何清除 System.Runtime.Caching.MemoryCache

重新生成designer.cs

我可以在加载事件时从 C# 的 div 标记中动态添加 HTML 吗?

Visual Studio 2013 ASP.NET 项目中 Antlr 包的用途是什么?

如何将 DataTable 转换为类 Object?

jQuery Ajax 调用 - 成功设置变量值