HttpClient:运行时有条件设置AcceptEncoding压缩

问题描述 投票:0回答:4

我们正在尝试在使用

HttpClient
的客户端中实现用户确定的(在设置屏幕上)可选的 gzip 压缩,因此我们可以记录并比较一段时间内多个不同调用的性能。我们的第一次尝试是简单地有条件地添加标头,如下所示:

HttpRequestMessage request = new HttpRequestMessage(Method, Uri);
if (AcceptGzipEncoding)
{
     _client.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip"));
}

//Send to the server
result = await _client.SendAsync(request);

//Read the content of the result response from the server
content = await result.Content.ReadAsStringAsync();

这创建了正确的请求,但 gzip 压缩的响应在返回时未解压缩,导致响应出现乱码。我发现我们在构建

HttpClientHandler
时必须包含
HttpClient
:

HttpClient _client = new HttpClient(new HttpClientHandler
    { 
        AutomaticDecompression = DecompressionMethods.GZip
    });

这一切都运行良好,但我们希望更改客户端是否在运行时

发送 
Accept-Encoding: gzip 标头,并且在将 HttpClientHandler
 传递给
HttpClient
构造函数。此外,如果请求的标头是由 
HttpRequestMessage
 定义的,则更改 
HttpClientHandler
 对象的标头不会对请求标头产生任何影响。

有什么方法可以做到这一点,而无需每次更改时重新创建

HttpClient

编辑:我还尝试修改对

HttpClientHandler

 的引用以在运行时更改 
AutomaticDecompression
,但这会引发此异常:

此实例已启动一个或多个请求。属性只能在发送第一个请求之前修改。

c# gzip .net-4.5 dotnet-httpclient winrt-async
4个回答
15
投票
第一个例子你已经差不多完成了,你只需要自己放气即可。 MS 的

GZipSteam 将对此提供帮助:

HttpRequestMessage request = new HttpRequestMessage(Method, Uri); if (AcceptGzipEncoding) { _client.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); } //Send to the server result = await _client.SendAsync(request); //Read the content of the result response from the server using (Stream stream = await result.Content.ReadAsStreamAsync()) using (Stream decompressed = new GZipStream(stream, CompressionMode.Decompress)) using (StreamReader reader = new StreamReader(decompressed)) { content = reader.ReadToEnd(); }
    

9
投票
如果您想使用同一个HttpClient并且只想对某些请求启用压缩,则无法使用自动解压缩。启用自动解压缩后,框架还会重置响应的

Content-Encoding

 标头。这意味着您无法确定响应是否真的被压缩。顺便说一句,如果您打开自动解压缩,响应的 
Content-Length
 标头也与解压缩内容的大小相匹配。 

所以需要手动解压内容。以下示例显示了 gzip 压缩内容的实现(也如 @ToddMenier 的

response 中所示):

private async Task<string> ReadContentAsString(HttpResponseMessage response) { // Check whether response is compressed if (response.Content.Headers.ContentEncoding.Any(x => x == "gzip")) { // Decompress manually using (var s = await response.Content.ReadAsStreamAsync()) { using (var decompressed = new GZipStream(s, CompressionMode.Decompress)) { using (var rdr As New IO.StreamReader(decompressed)) { return await rdr.ReadToEndAsync(); } } } else // Use standard implementation if not compressed return await response.Content.ReadAsStringAsync(); }
    

2
投票
根据上面的评论,重新创建 HttpClient 实际上是执行此操作的唯一(可靠)方法。可以实现手动解压缩,但似乎很难可靠/有效地确定内容是否已编码,以确定是否应用解码。


0
投票
我最近遇到了这个问题。我解决了这个问题,创建了客户端通知自动解压缩。

_client = new HttpClient(new HttpClientHandler { AutomaticDecompression = System.Net.DecompressionMethods.Deflate })


    

© www.soinside.com 2019 - 2024. All rights reserved.