压缩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() { }
- 使用AngularJS从ASP.NET Web API方法下载文件
- entity framework在运行时更改连接
- AngularJS CORS问题
- validation从移动(iPhone)应用程序到ASP.Net Web API的请求(请在我的devise中提供反馈)
- 为什么要创buildasynchronousWebAPI操作而不是同步?
- 如何在ASP.NET Web Api中testingAction Filter?
- 如何在C#中编写Json文件?
- ASP.NET Web API – 不允许PUT&DELETE动词 – IIS 8
- WebAPI 2中的DefaultInlineConstraintResolver错误