仕事で利用していたクラウドサービスのAPIの仕様で、リクエスト都度で認証する必要があり、ハマったので備忘録にしておきます。
当初は以下のようにHttpClientでAPIをコールしていたのですが、一度認証されるとそのセッションが使いまわされてしまいます。
HttpClientをDisposeすることでもコネクションを破棄することもできるのですが、それはそれでソケットの枯渇という別の問題も生みます。
開発者を苦しめる.NETのHttpClientのバグと紛らわしいドキュメント
// HttpClientインスタンスはstatic変数として使いまわす private static HttpClient httpClient = new HttpClient() // リクエスト生成 var request = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri("http://ohke.hateblo.jp/") }; // Basic認証ヘッダを付与する request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, userPassword)))); // リクエストの送信 var response = await httpClient.SendAsync(request);
リクエスト都度認証させるためにはKeep-Aliveを無効にして、HTTPのConnectionヘッダをCloseにする必要があります(これに気付かされるのも時間がかかったのですが)。
HttpWebRequestにはKeepAliveプロパティをfalseにすれば良いのですが、HttpClientを使う場合はHttpRequestMessageのHeadersプロパティ(またはHttpClientのDefaultRequestHeaders)に直接書き加える必要があります。
これでリクエストヘッダがConnection: Close
となり、Keep-Aliveが無効になります。
// Basic認証ヘッダを付与する request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, userPassword)))); // Keep-Aliveをオフにする(リクエスト都度認証させる) request.Headers.Add("Connection", "close"); // リクエストの送信 var response = await httpClient.SendAsync(request);
通常は一度認証したセッションは使いまわすべきなので、レアケースかとは思います。