【问题标题】:Azure App Service- GZip Compression in RequestAzure 应用服务 - 请求中的 GZip 压缩
【发布时间】:2018-07-30 23:48:54
【问题描述】:

使用此代码(没有请求压缩部分),我可以从 Azure 应用服务(具有离线同步功能的 Xamarin.Froms 应用)获取 gzip 压缩内容。但是当我尝试 gzip 请求 http-content 时,我得到一个“错误请求”。

有什么想法吗?是否可以使用 Azure 应用服务对请求内容进行 gzip 压缩?

namespace XXX.XXX.XXX.XXX.XXX
{
    public class HttpGZipClientHandler : System.Net.Http.HttpClientHandler
    {
        long time = 0;
        private long _downloadedBytesFromServer;
        private long _downloadedProcessedBytes;
        private long _intendedUploadedBytesToServer;
        private long _uploadedBytesToServer;
        private long _additionalTimeOverhead = 0;

        public override bool SupportsAutomaticDecompression { get { return true; } }
        public long DownloadedBytesFromServer { get { return _downloadedBytesFromServer; } }
        public long DownloadedProcessedBytes { get { return _downloadedProcessedBytes; } }
        public long IntendedUploadedBytesToServer { get { return _intendedUploadedBytesToServer; } }
        public long UploadedBytesToServer { get { return _uploadedBytesToServer; } }
        public long AdditionalTimeOverhead { get { return _additionalTimeOverhead; } }

        public void ResetStatistics()
        {
            _downloadedBytesFromServer = 0;
            _downloadedProcessedBytes = 0;
            _intendedUploadedBytesToServer = 0;
            _uploadedBytesToServer = 0;
            _additionalTimeOverhead = 0;
        }

        protected override async Task<System.Net.Http.HttpResponseMessage> SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {

            //Save content headers before compressing
            System.Collections.Generic.Dictionary<string, System.Collections.Generic.IEnumerable<string>> savedContentHeaders = new Dictionary<string, IEnumerable<string>>();
            foreach (System.Collections.Generic.KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> keyValue in request.Content.Headers)
            {
                savedContentHeaders.Add(keyValue.Key, keyValue.Value);
            }

            //Compress request content
            System.Diagnostics.Stopwatch sp1 = new System.Diagnostics.Stopwatch();
            sp1.Start();

            _intendedUploadedBytesToServer += request.Content.Headers.ContentLength.HasValue ? request.Content.Headers.ContentLength.Value : 0;

            await request.Content.LoadIntoBufferAsync().ConfigureAwait(false);
            request.Content = new HttpGZipContent(await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false), System.IO.Compression.CompressionMode.Compress);

            byte[] uploadedBytes = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
            _uploadedBytesToServer += uploadedBytes.Length;

            sp1.Stop();
            _additionalTimeOverhead += sp1.ElapsedMilliseconds;

            //Set headers
            foreach (System.Collections.Generic.KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> keyValue in savedContentHeaders)
            {
                request.Content.Headers.Add(keyValue.Key, keyValue.Value);
            }

            request.Headers.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip"));
            request.Content.Headers.Add("Content-Encoding", "gzip");

            //Execute request
            System.Net.Http.HttpResponseMessage response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
            _downloadedBytesFromServer += response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : 0;

            //Decompress response content
            if (response.Content.Headers.ContentEncoding.Contains("gzip"))
            {
                System.Diagnostics.Stopwatch sp2 = new System.Diagnostics.Stopwatch();
                sp2.Start();

                await response.Content.LoadIntoBufferAsync().ConfigureAwait(false);
                response.Content = new HttpGZipContent(await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false), System.IO.Compression.CompressionMode.Decompress);

                byte[] processedBytes = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
                _downloadedProcessedBytes += processedBytes.Length;

                sp2.Stop();
                _additionalTimeOverhead += sp2.ElapsedMilliseconds;
            }
            else
                _downloadedProcessedBytes += response.Content.Headers.ContentLength.HasValue ? response.Content.Headers.ContentLength.Value : 0;

            return response;
        }
    }

    internal sealed class HttpGZipContent : System.Net.Http.HttpContent
    {
        private readonly byte[] _content;
        private readonly System.IO.Compression.CompressionMode _compressionMode;

        public HttpGZipContent(byte[] content, System.IO.Compression.CompressionMode compressionMode)
        {
            _compressionMode = compressionMode;
            _content = content;
        }

        protected override async System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext context)
        {
            if (_compressionMode == System.IO.Compression.CompressionMode.Compress)
            {
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(_content.Length))
                {
                    using (System.IO.Compression.GZipStream zipStream = new System.IO.Compression.GZipStream(memoryStream, System.IO.Compression.CompressionMode.Compress))
                    {
                        zipStream.Write(_content, 0, _content.Length);
                        zipStream.Flush();
                    }

                    byte[] compressed = memoryStream.ToArray();
                    System.IO.MemoryStream copyStream = new System.IO.MemoryStream(compressed);
                    await copyStream.CopyToAsync(stream).ConfigureAwait(false);
                }
            }
            else
            {
                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(_content, 0, _content.Length))
                {
                    using (System.IO.Compression.GZipStream zipStream = new System.IO.Compression.GZipStream(memoryStream, System.IO.Compression.CompressionMode.Decompress))
                    {
                        await zipStream.CopyToAsync(stream).ConfigureAwait(false);
                    }
                }
            }
        }

        protected override bool TryComputeLength(out long length)
        {
            length = _content.Length;
            return true;
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
    }
}

【问题讨论】:

    标签: c# azure xamarin asp.net-web-api azure-mobile-services


    【解决方案1】:

    根据我的理解,您需要为您的移动应用后端实现请求解压。如果您使用的是 C# 后端,您可以创建自定义 ActionFilterAttribute,如下所示:

    public class RequestDeCompressFilter : ActionFilterAttribute
    {
        public override async Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            var request = actionContext.Request;
            if (request.Content.Headers.ContentEncoding.Contains("GZIP"))
            {
                await request.Content.LoadIntoBufferAsync().ConfigureAwait(false);
                request.Content = new HttpGZipContent(await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false), System.IO.Compression.CompressionMode.Decompress);
            }
           //TODO: compress the response, you could follow http://www.intstrings.com/ramivemula/articles/jumpstart-47-gzipdeflate-compression-in-asp-net-mvc-application/
           await base.OnActionExecutingAsync(actionContext, cancellationToken);
        }
    
        public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
        {   
            //you could also compress the response here
            return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
        }
    }
    

    然后,将您的操作标记如下:

    [RequestDeCompressFilter]
    public async Task<IHttpActionResult> PostMessage(Message item)
    

    另外,您可以按照 HTTP Message Handlers in ASP.NET Web API 来实现您的 HTTP 消息处理程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 2019-05-07
      • 2010-12-17
      • 2011-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多