在我的应用程序中,我们从客户端发送大小合适的数据包,并收到相当大的响应,所以我想在上升和返回的过程中实现一些压缩。
在回来的路上很好,因为我可以依靠IIS的动态压缩为我做这件事,但在上升的过程中,我发现了以下问题。
我有一个代理处理程序,可以解压缩传入的请求: (此代码的大部分内容基于Fabrik.Common(https://github.com/benfoster/Fabrik.Common))
的部分内容public class DecompressionHandler : DelegatingHandler
{
public Collection<ICompressor> Compressors;
public DecompressionHandler()
{
Compressors = new Collection<ICompressor> {new GZipCompressor(), new DeflateCompressor()};
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentEncoding.IsntNullOrEmpty() && request.Content != null)
{
var encoding = request.Content.Headers.ContentEncoding.First();
var compressor = Compressors.FirstOrDefault(c => c.EncodingType.Equals(encoding, StringComparison.InvariantCultureIgnoreCase));
if (compressor != null)
{
request.Content = await DecompressContentAsync(request.Content, compressor).ConfigureAwait(true);
}
}
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(true);
return response;
}
private static async Task<HttpContent> DecompressContentAsync(HttpContent compressedContent, ICompressor compressor)
{
using (compressedContent)
{
var decompressed = new MemoryStream();
await compressor.Decompress(await compressedContent.ReadAsStreamAsync(), decompressed).ConfigureAwait(true);
// set position back to 0 so it can be read again
decompressed.Position = 0;
var newContent = new StreamContent(decompressed);
// copy content type so we know how to load correct formatter
newContent.Headers.ContentType = compressedContent.Headers.ContentType;
return newContent;
}
}
}
public class DeflateCompressor : Compressor
{
private const string DeflateEncoding = "deflate";
public override string EncodingType
{
get { return DeflateEncoding; }
}
public override Stream CreateCompressionStream(Stream output)
{
return new DeflateStream(output, CompressionMode.Compress, leaveOpen: true);
}
public override Stream CreateDecompressionStream(Stream input)
{
return new DeflateStream(input, CompressionMode.Decompress, leaveOpen: true);
}
}
public abstract class Compressor : ICompressor
{
public abstract string EncodingType { get; }
public abstract Stream CreateCompressionStream(Stream output);
public abstract Stream CreateDecompressionStream(Stream input);
public virtual Task Compress(Stream source, Stream destination)
{
var compressed = CreateCompressionStream(destination);
return Pump(source, compressed)
.ContinueWith(task => compressed.Dispose());
}
public virtual Task Decompress(Stream source, Stream destination)
{
var decompressed = CreateDecompressionStream(source);
return Pump(decompressed, destination)
.ContinueWith(task => decompressed.Dispose());
}
protected virtual Task Pump(Stream input, Stream output)
{
return input.CopyToAsync(output);
}
}
public interface ICompressor
{
string EncodingType { get; }
Task Compress(Stream source, Stream destination);
Task Decompress(Stream source, Stream destination);
}
public class GZipCompressor : Compressor
{
private const string GZipEncoding = "gzip";
public override string EncodingType
{
get { return GZipEncoding; }
}
public override Stream CreateCompressionStream(Stream output)
{
return new GZipStream(output, CompressionMode.Compress, leaveOpen: true);
}
public override Stream CreateDecompressionStream(Stream input)
{
return new GZipStream(input, CompressionMode.Decompress, leaveOpen: true);
}
}
解压缩工作正常,我有我的request.Content填充结果是我的解压缩JSON。
当我将它传递给base.SendAsync并且它命中我的控制器方法时,模型为null,而在我实现压缩之前,它一切都很好。
我已经读过,当您阅读内容流时,它是一次性的事情,但我认为将request.content设置为解压缩的结果应该让它再次被读取?
答案 0 :(得分:2)
我解决了这个问题。
我的HTTPClient实现中出现错误,我已经从使用PostAsJsonAsync转移到PostAsync来执行压缩客户端,但是没有添加Content-Type标头来指定application / json。
在客户端完成此操作后,所有操作都按计划进行。