我们正在尝试在使用
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
,但这会引发此异常:
此实例已启动一个或多个请求。属性只能在发送第一个请求之前修改。
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();
}
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();
}
_client = new HttpClient(new HttpClientHandler { AutomaticDecompression = System.Net.DecompressionMethods.Deflate })