WebAPI Gzip when returning HttpResponseMessage

后端 未结 4 544
心在旅途
心在旅途 2021-01-30 09:13

I have a WebAPI controller that returns an HttpResponseMessage and I want to add gzip compression. This is the server code:

using System.Net.Http;
u         


        
4条回答
  •  遥遥无期
    2021-01-30 10:03

    One Solution without editing any IIS Setting or Installing any Nuget package is to add a MessageHandler to your WEB API.

    This will catch requests with the "AcceptEncoding" Header and compress them using the Build in System.IO.Compression libraries.

    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 SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            return base.SendAsync(request, cancellationToken).ContinueWith((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> 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();
                }
            });
        }
    }
    

    And add this handler to your Global.asax.cs

    GlobalConfiguration.Configuration.MessageHandlers.Insert(0, CompressHandler.GetSingleton());
    

    Kudos to Ben Foster. ASP.NET Web API Compression

提交回复
热议问题