压缩HTTP GET响应

我目前正在将less数MVC3控制器迁移到MVC4 Api控制器。 我已经实现了MVC3控制器Get方法响应的压缩机制,通过embeddedActionFilterAttribute并重写OnActionExecutiong方法。 经过一番研究,我发现我需要使用System.Web.HttpFilters ActionFilterMethod 。 如果有人能够共享一段示例代码来让我开始使用GZip压缩HTTP响应,那将是非常好的

最简单的是直接在IIS级别启用压缩 。

如果您想在应用程序级别执行此操作,则可以编写自定义委派消息处理程序,如以下文章所示:

 public class CompressHandler : 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) { 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.AddWithoutValidation(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(); } }); } } 

现在剩下的就是在Application_Start注册处理Application_Start

 GlobalConfiguration.Configuration.MessageHandlers.Add(new CompressHandler()); 

如果你使用的是IIS 7+,我会说压缩到IIS,因为它支持GZIP压缩。 只要打开它 。

另一方面,压缩距离控制器的金属太近。 理想情况下,控制器应该比字节和数据stream工作在更高的水平。

使用一个类并写下面的代码

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class CompressFilter : ActionFilterAttribute { public override void OnActionExecuted(HttpActionExecutedContext context) { var acceptedEncoding = context.Response.RequestMessage.Headers.AcceptEncoding.First().Value; if (!acceptedEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase) && !acceptedEncoding.Equals("deflate", StringComparison.InvariantCultureIgnoreCase)) { return; } context.Response.Content = new CompressedContent(context.Response.Content, acceptedEncoding); } } 

现在创build另一个类并写下面的代码。

 public class CompressedContent : HttpContent { private readonly string _encodingType; private readonly HttpContent _originalContent; public CompressedContent(HttpContent content, string encodingType = "gzip") { if (content == null) { throw new ArgumentNullException("content"); } _originalContent = content; _encodingType = encodingType.ToLowerInvariant(); foreach (var header in _originalContent.Headers) { Headers.TryAddWithoutValidation(header.Key, header.Value); } 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; switch (_encodingType) { case "gzip": compressedStream = new GZipStream(stream, CompressionMode.Compress, true); break; case "deflate": compressedStream = new DeflateStream(stream, CompressionMode.Compress, true); break; default: compressedStream = stream; break; } return _originalContent.CopyToAsync(compressedStream).ContinueWith(tsk => { if (compressedStream != null) { compressedStream.Dispose(); } }); } } 

现在在控制器或者像这样的任何api动作方法中使用以下属性

 [Route("GetData")] [CompressFilter] public HttpResponseMessage GetData() { }