Azure 应用服务 - 请求中的 GZip 压缩
Posted
技术标签:
【中文标题】Azure 应用服务 - 请求中的 GZip 压缩【英文标题】:Azure App Service- GZip Compression in Request 【发布时间】: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);
【问题讨论】:
【参考方案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 消息处理程序。
【讨论】:
以上是关于Azure 应用服务 - 请求中的 GZip 压缩的主要内容,如果未能解决你的问题,请参考以下文章