使用此代码(没有请求压缩部分),我能够从Azure App Service(具有脱机同步的Xamarin.Froms App)获取gzip压缩内容。但是,当我尝试gzip请求http-content时,我得到了一个" Bad Request"。
有什么想法吗?是否可以使用Azure App Service 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);
}
}
}
答案 0 :(得分:0)
根据我的理解,您需要为移动应用后端实施请求解压缩。如果您使用的是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消息处理程序。