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
への参照も変更しようとしましたが、この例外がスローされます。
このインスタンスはすでに1つ以上のリクエストを開始しています。プロパティは、最初のリクエストを送信する前にのみ変更できます。
上記のコメントによると、HttpClientを再作成することが、これを行う唯一の(堅牢な)方法です。手動で解凍することはできますが、コンテンツがエンコードされているかどうかを確実に/効率的に判断し、デコードを適用するかどうかを判断することは非常に難しいようです。
最初の例でほぼ完了です。ストリームを自分で収縮させる必要があります。 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();
}
同じ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();
}