使用 HttpClient 将请求压缩到 asp.net 核心 2 站点的最佳方法是什么?
What is the best way to compress a request to asp.net core 2 site using HttpClient?
我发送的请求可能非常大 (~1Mb),我发现在发出请求和 asp.net 核心记录它正在处理请求之间存在很大的延迟。我想我可以通过使用 gzip 将请求压缩到 asp 来缩短时间。
下面是我在没有压缩的情况下发出请求的相当直接的方式。在客户端请求端实现 Gzip 请求压缩的正确方法是什么,一旦我在客户端实现它,我需要为服务器端做些什么?
using (HttpResponseMessage response = client.PostAsync("Controller/Action", httpContent).Result)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(string.Format("Invalid responsecode for http request response {0}: {1}", response.StatusCode, response.ReasonPhrase));
}
}
您可能需要启用压缩,如下所示
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
var client = new HttpClient(handler);
所以我让它在服务器端使用简单的中间件,而不是在客户端做太多工作。我使用 CompressedContent.cs from WebAPIContrib,正如雷克斯在他的回答的评论中所建议的那样,并提出了如下所示的请求。整个 throw-exception-if-not-OK 是因为我使用 Polly 包裹我的请求并重试并等待策略。
客户端:
using (var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json"))
using (var compressedContent = new CompressedContent(httpContent, "gzip"))
using (HttpResponseMessage response = client.PostAsync("Controller/Action", compressedContent).Result)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(string.Format("Invalid responsecode for http request response {0}: {1}", response.StatusCode, response.ReasonPhrase));
}
}
然后在服务器端我创建了一个简单的中间件,它用 Gzip 流包装请求主体流。要使用它,您需要在 Startup.cs
的 Configure
方法中的 调用 app.UseMvc();
之前添加行 app.UseMiddleware<GzipRequestMiddleware>();
。
public class GzipRequestMiddleware
{
private readonly RequestDelegate next;
private const string ContentEncodingHeader = "Content-Encoding";
private const string ContentEncodingGzip = "gzip";
private const string ContentEncodingDeflate = "deflate";
public GzipRequestMiddleware(RequestDelegate next)
{
this.next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains(ContentEncodingHeader) && (context.Request.Headers[ContentEncodingHeader] == ContentEncodingGzip || context.Request.Headers[ContentEncodingHeader] == ContentEncodingDeflate))
{
var contentEncoding = context.Request.Headers[ContentEncodingHeader];
var decompressor = contentEncoding == ContentEncodingGzip ? (Stream)new GZipStream(context.Request.Body, CompressionMode.Decompress, true) : (Stream)new DeflateStream(context.Request.Body, CompressionMode.Decompress, true);
context.Request.Body = decompressor;
}
await next(context);
}
}
我发送的请求可能非常大 (~1Mb),我发现在发出请求和 asp.net 核心记录它正在处理请求之间存在很大的延迟。我想我可以通过使用 gzip 将请求压缩到 asp 来缩短时间。
下面是我在没有压缩的情况下发出请求的相当直接的方式。在客户端请求端实现 Gzip 请求压缩的正确方法是什么,一旦我在客户端实现它,我需要为服务器端做些什么?
using (HttpResponseMessage response = client.PostAsync("Controller/Action", httpContent).Result)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(string.Format("Invalid responsecode for http request response {0}: {1}", response.StatusCode, response.ReasonPhrase));
}
}
您可能需要启用压缩,如下所示
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
var client = new HttpClient(handler);
所以我让它在服务器端使用简单的中间件,而不是在客户端做太多工作。我使用 CompressedContent.cs from WebAPIContrib,正如雷克斯在他的回答的评论中所建议的那样,并提出了如下所示的请求。整个 throw-exception-if-not-OK 是因为我使用 Polly 包裹我的请求并重试并等待策略。
客户端:
using (var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json"))
using (var compressedContent = new CompressedContent(httpContent, "gzip"))
using (HttpResponseMessage response = client.PostAsync("Controller/Action", compressedContent).Result)
{
if (response.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception(string.Format("Invalid responsecode for http request response {0}: {1}", response.StatusCode, response.ReasonPhrase));
}
}
然后在服务器端我创建了一个简单的中间件,它用 Gzip 流包装请求主体流。要使用它,您需要在 Startup.cs
的 Configure
方法中的 调用 app.UseMvc();
之前添加行 app.UseMiddleware<GzipRequestMiddleware>();
。
public class GzipRequestMiddleware
{
private readonly RequestDelegate next;
private const string ContentEncodingHeader = "Content-Encoding";
private const string ContentEncodingGzip = "gzip";
private const string ContentEncodingDeflate = "deflate";
public GzipRequestMiddleware(RequestDelegate next)
{
this.next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.Keys.Contains(ContentEncodingHeader) && (context.Request.Headers[ContentEncodingHeader] == ContentEncodingGzip || context.Request.Headers[ContentEncodingHeader] == ContentEncodingDeflate))
{
var contentEncoding = context.Request.Headers[ContentEncodingHeader];
var decompressor = contentEncoding == ContentEncodingGzip ? (Stream)new GZipStream(context.Request.Body, CompressionMode.Decompress, true) : (Stream)new DeflateStream(context.Request.Body, CompressionMode.Decompress, true);
context.Request.Body = decompressor;
}
await next(context);
}
}