【发布时间】: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