fre*_*hie 28 c# asp.net jquery gzip asp.net-web-api
我有一个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);
}
Run Code Online (Sandbox Code Playgroud)
这是使用jquery的ajax调用的客户端代码:
$.ajax({
url: "/SomeRoute",
type: "POST",
cache: "false",
data: SomeData,
beforeSend: function (jqXHR) { jqXHR.setRequestHeader('Accept-Encoding', 'gzip'); },
success: function(msg) { ... }
Run Code Online (Sandbox Code Playgroud)
当我运行它时,服务器代码返回没有错误,但客户端错误:
(failed)
net::ERR_CONTENT_DECODING_FAILED
Run Code Online (Sandbox Code Playgroud)

当我和Fiddler一起看时,这就是我所看到的:

我需要更改什么才能使Web服务返回客户端正常处理的gzip压缩内容?我知道我也可以使用HttpModule或通过IIS上的某些设置来执行此操作,但这两个选项都不适合托管的情况:

请注意,我不是在寻找IIS设置,因为我无权访问(托管).
Poo*_*ran 48
添加这些NuGet包:
Microsoft.AspNet.WebApi.Extensions.Compression.Server System.Net.Http.Extensions.Compression.Client
然后添加一行代码App_Start\WebApiConfig.cs:
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, new ServerCompressionHandler(new GZipCompressor(), new DeflateCompressor()));
Run Code Online (Sandbox Code Playgroud)
那就行了!
详细信息:
希望有所帮助.
**@JCisar发表评论后更新
ASP.Net Core的更新
Nuget包是
Microsoft.AspNetCore.ResponseCompression
dmp*_*lla 23
如果您有权访问IIS配置
你不能只应用标题,并希望它将被gzip压缩 - 响应将不会被压缩.
您需要删除添加的标头,并确保在IIS服务器上启用了动态压缩和静态内容压缩.
其中一位评论者在stakoverflow上提到了一个很好的资源链接,展示了如何做到这一点:
请注意,如果已安装动态压缩(不在IIS的默认安装中),它将仅在web.config中设置值
您可以在MSDN文档中找到有关此内容的信息:http://www.iis.net/configreference/system.webserver/httpcompression
简单的压缩
下面是使用一个简单的自己进行压缩的例子,这个例子是使用visual studio项目模板中的Web Api MVC 4项目.要使压缩工作HttpResponseMessages,您必须实现自定义MessageHandler.请参见下面的工作示例.
请参阅下面的代码实现.
请注意,我试图让方法与您的示例保持一致.
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();
}
});
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
还要将新消息处理程序添加到应用程序的配置中.
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
自定义处理程序由 - Kiran Challa(http://blogs.msdn.com/b/kiranchalla/archive/2012/09/04/handling-compression-accept-encoding-sample.aspx)组合在一起.
有更好的示例可以实现入站流的缩小,您可以看到以下示例:
另外,我发现了一个非常好的项目,它支持github上的所有这些.
请注意,当我自己到达这个答案时,Simon在你的评论中提出了这个方法,从这个答案之日起2天前.
一种无需编辑任何IIS设置或安装任何Nuget软件包的解决方案是将MessageHandler添加到您的WEB API。
这将使用“ AcceptEncoding”标头捕获请求,并使用System.IO.Compression库中的Build压缩请求。
public class CompressHandler : DelegatingHandler
{
private static CompressHandler _handler;
private CompressHandler(){}
public static CompressHandler GetSingleton()
{
if (_handler == null)
_handler = new CompressHandler();
return _handler;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>((responseToCompleteTask) =>
{
HttpResponseMessage response = responseToCompleteTask.Result;
var acceptedEncoding =GetAcceptedEncoding(response);
if(acceptedEncoding!=null)
response.Content = new CompressedContent(response.Content, acceptedEncoding);
return response;
},
TaskContinuationOptions.OnlyOnRanToCompletion);
}
private string GetAcceptedEncoding(HttpResponseMessage response)
{
string encodingType=null;
if (response.RequestMessage.Headers.AcceptEncoding != null && response.RequestMessage.Headers.AcceptEncoding.Any())
{
encodingType = response.RequestMessage.Headers.AcceptEncoding.First().Value;
}
return encodingType;
}
}
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();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
并将此处理程序添加到您的Global.asax.cs
GlobalConfiguration.Configuration.MessageHandlers.Insert(0, CompressHandler.GetSingleton());
Run Code Online (Sandbox Code Playgroud)
感谢本·福斯特(Ben Foster)。 ASP.NET Web API压缩