• システム開発に関わる内容をざっくりと書いていく

C# HttpClient タイムアウト設定方法

HttpClient で外部 API を叩いていると、「たまに固まる」「タイムアウトで落ちる」が起きやすい。設定箇所が複数あるので、逆引きできるように整理する。

この記事では、どこにタイムアウトがあるか現場での決め方をざっくりまとめる。


先に結論

よく触るタイムアウトは次の3つ。

  • HttpClient.Timeout:リクエスト全体の上限(デフォルト 100 秒)
  • CancellationToken:呼び出し側で打ち切る
  • 接続系(SocketsHttpHandler など):接続確立の待ち時間

まずは HttpClient.TimeoutCancellationToken を押さえると実務の大半はカバーできる。


基本:HttpClient.Timeout

using var client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(30)
};

var response = await client.GetAsync("https://example.com/api");

この値を超えると TaskCanceledException(内側にタイムアウト起因)になりやすい。メッセージだけ見るとキャンセルに見えて紛らわしい。


推奨:IHttpClientFactory + Timeout

// Program.cs
builder.Services.AddHttpClient("external-api", client =>
{
client.BaseAddress = new Uri("https://example.com/");
client.Timeout = TimeSpan.FromSeconds(15);
});
public class ApiService(IHttpClientFactory factory)
{
public async Task<string> GetAsync()
{
var client = factory.CreateClient("external-api");
return await client.GetStringAsync("/data");
}
}

new HttpClient() の連発はソケット枯渇の原因になる。ASP.NET Core なら Factory 経由が基本。


CancellationToken で打ち切る

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var response = await client.GetAsync(url, cts.Token);

「この画面操作は 5 秒で諦めたい」など、呼び出し単位の制御に向く。HttpClient.Timeout より細かく止められる。


よくあるハマり

  • 例外が TaskCanceledException で、原因がタイムアウトか本当のキャンセルか分からない
  • HttpClient は長い Timeout のまま、個別呼び出しだけ短い Token を付け忘れる
  • サーバ側タイムアウト(IIS / リバプロ / API ゲートウェイ)と二重管理になる
  • リトライして、タイムアウト合計が想定より長くなる

切り分け手順

  1. クライアント側の Timeout / CancellationToken を確認
  2. サーバや途中プロキシのタイムアウトを確認
  3. 遅いのは DNS / 接続 / レスポンス待ちのどこかを切り分ける
  4. 必要ならリトライ(冪等な GET など)とセットで設計する

ざっくりまとめ

  • 全体上限は HttpClient.Timeout
  • 呼び出し単位は CancellationToken
  • ASP.NET Core では IHttpClientFactory を使う
  • 例外名だけで判断せず、タイムアウト起因かをログに残す