HttpClientがタイムアウトしたことを確認するにはどうすればよいですか?


142

私の知る限り、具体的にはタイムアウトが発生したことを知る方法はありません。私は正しい場所を探していませんか、それとももっと大きなものを見逃していますか?

string baseAddress = "http://localhost:8080/";
var client = new HttpClient() 
{ 
    BaseAddress = new Uri(baseAddress), 
    Timeout = TimeSpan.FromMilliseconds(1) 
};
try
{
    var s = client.GetAsync("").Result;
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine(e.InnerException.Message);
}

これは次を返します:

1つ以上のエラーが発生しました。

タスクがキャンセルされました。


3
私たちは、GitHubの上の問題をupvoteすることができますのHttpClientは20296タイムアウト#上TaskCanceledExceptionを投げる
csrowell

質問に対する巨大な賛成票。また... UWPでこれを行う方法はありますか?そのWindows.Web.HTTP.HTTPClientにはタイムアウトメンバーがありません。また、GetAsyncメソッドはキャンセルトークンを受け入れません...
Do-do-new '

1
6年後、クライアントがタイムアウトしたかどうかはまだわかりません。
スティーブスミス

回答:


61

GetAsyncメソッドを待つ必要があります。次に、TaskCanceledExceptionタイムアウトした場合にをスローします。さらに、タイムアウトGetStringAsyncGetStreamAsync内部的に処理するため、例外がスローされることはありません。

string baseAddress = "http://localhost:8080/";
var client = new HttpClient() 
{ 
    BaseAddress = new Uri(baseAddress), 
    Timeout = TimeSpan.FromMilliseconds(1) 
};
try
{
    var s = await client.GetAsync();
}
catch(Exception e)
{
    Console.WriteLine(e.Message);
    Console.WriteLine(e.InnerException.Message);
}

2
私はこれをテストし、私にGetStreamAsync投げTaskCanceledExceptionました。
サム

38
TaskCanceledException直接のキャンセルやその他の理由で、HTTPタイムアウトが原因かどうかはどうやってわかりますか?
UserControl、2014年

8
@UserControlチェックTaskCanceledException.CancellationToken.IsCancellationRequested。falseの場合、それがタイムアウトであったと合理的に確信できます。
Todd Menier、2014

3
結局のところ、IsCancellationRequested以前考えたように、直接キャンセル時に例外のトークンを設定することは期待できません
。stackoverflow.com/ q

2
@testing彼らは異なる振る舞いをしません。ユーザーのキャンセルリクエストを表す1つのトークンと、クライアントのタイムアウトを表す内部(アクセスできず、不要)があるだけです。それが異なるのはユースケースです
Rufo卿'06 /

59

私は同じ問題を再現していますが、それは本当に迷惑です。私はこれらが便利だと思った

HttpClient-集計例外の処理

HttpClient.GetAsyncのバグは、TaskCanceledExceptionではなく、WebExceptionをスローするはずです。

リンクがどこにも行かない場合のいくつかのコード:

var c = new HttpClient();
c.Timeout = TimeSpan.FromMilliseconds(10);
var cts = new CancellationTokenSource();
try
{
    var x = await c.GetAsync("http://linqpad.net", cts.Token);  
}
catch(WebException ex)
{
    // handle web exception
}
catch(TaskCanceledException ex)
{
    if(ex.CancellationToken == cts.Token)
    {
        // a real cancellation, triggered by the caller
    }
    else
    {
        // a web request timeout (possibly other things!?)
    }
}

私の経験では、WebExceptionはどのような状況でも捕捉できません。他の人は何か違うことを経験していますか?
2015年

1
@crushをキャッチWebException できます。おそらくこれは役立つでしょう。
DavidRR

私がctsを使用していない場合、これは私にとってはうまくいきません。私はただTask <T>を使用していますtask = SomeTask()try {T result = task.Result} catch(TaskCanceledException){} catch(Exception e){} TaskCanceledExceptionではなく、一般的な例外のみがキャッチされます。私のバージョンのコードの何が問題になっていますか?
直美

1
元のバグレポートがアーカイブされたフォーラム投稿にあるように見えるため、新しいバグレポートを作成しました:connect.microsoft.com/VisualStudio/feedback/details/3141135
StriplingWarrior

1
トークンが外部から渡された場合、default(CancellationToken)それはと比較する前ではありませんex.CancellationToken
SerG、

25

サービス呼び出しがタイムアウトしたかどうかを判断する最良の方法は、HttpClientのタイムアウトプロパティではなくキャンセルトークンを使用することです。

var cts = new CancellationTokenSource();
cts.CancelAfter(timeout);

そして、サービス呼び出し中にCancellationExceptionを処理します...

catch(TaskCanceledException)
{
    if(!cts.Token.IsCancellationRequested)
    {
        // Timed Out
    }
    else
    {
        // Cancelled for some other reason
    }
}

もちろん、サービス側でタイムアウトが発生した場合は、WebExceptionで処理できるはずです。


1
うーん、このサンプルを有効にするには、否定演算子(編集で追加されたもの)を削除する必要があると思いますか?場合cts.Token.IsCancellationRequestedtrueは、タイムアウトが発生したことを意味する必要がありますか?
Lasse Christiansen

9

http://msdn.microsoft.com/en-us/library/system.net.http.httpclient.timeout.aspxから

ドメインネームシステム(DNS)クエリが返されるか、タイムアウトするまでに最大15秒かかることがあります。リクエストに解決が必要なホスト名が含まれていて、タイムアウトを15秒未満の値に設定した場合、リクエストのタイムアウトを示すためにWebExceptionがスローされるまでに15秒以上かかることがあります

次に、Statusプロパティにアクセスします。WebExceptionStatusを参照してください。


3
フム、私は戻ってきてるAggregateExceptionTaskCancelledException内部。私は何か間違ったことをしているに違いありません...
Benjol

使っていcatch(WebException e)ますか?
user247702

いいえ、私が試しても、AggregateException処理されません。VSコンソールプロジェクトを作成し、への参照を追加しSystem.Net.Httpてコードをmainにドロップすると、(必要に応じて)自分で確認できます。
Benjol

5
待機期間がタスクのタイムアウト期間を超えると、を取得しTaskCanceledExceptionます。これは、TPLの内部タイムアウト処理によってスローされたようですHttpWebClient。そこは良い方法ではないようですタイムアウトキャンセルとユーザーのキャンセルを区別します。この結果として、WebException内にを取得できない場合がありますAggregateException
JT。

1
他の人が言ったように、TaskCanceledExceptionがタイムアウトであると想定する必要があります。try {//ここにコードを
挿入

8

基本的に、をキャッチしてOperationCanceledException、渡されたキャンセルトークンの状態をチェックする必要がありますSendAsync(またはGetAsync、またはHttpClient使用しているメソッド)。

  • キャンセルされた場合(IsCancellationRequestedtrue)、リクエストが本当にキャンセルされたことを意味します
  • そうでない場合は、リクエストがタイムアウトしたことを意味します

もちろん、これはあまり便利ではありません... TimeoutExceptionタイムアウトの場合はを受け取るほうがよいでしょう。ここでは、カスタムHTTPメッセージハンドラーに基づくソリューションを提案します。HttpClientでのタイムアウト処理の改善


ああ!それはあなたです!今日の初めにあなたのブログ記事にコメントを書きました。しかし、この回答に関しては、IsCancellationRequestedについてのあなたの指摘は真実ではないと思います。私が自分でキャンセルしなかった場合、私にとっては常に真実であるように思われます
knocte

@knocteそれは奇妙です...しかし、その場合、私のブログ投稿からのソリューションは、これにも依存しているため、役に立ちません
Thomas Levesque

1
これに関するgithubの問題では、多くの人が私が言ったことを主張します。IsCancellationRequestedはタイムアウトが発生したときにtrueになるということです。だから私はあなたの答えに反対票を投じる誘惑に駆られます;)
knocte '21

@knocte、何を言えばいいのかわからない...私はこれを長い間使用してきましたが、いつもうまくいきました。HttpClient.Timeoutを無限大に設定しましたか?
Thomas Levesque

いいえ、私は自分でHttpClientを制御できないため、しませんでした。これは、私が使用している
サードパーティ

-1
_httpClient = new HttpClient(handler) {Timeout = TimeSpan.FromSeconds(5)};

私がいつもやっていることですが、私にとってはかなりうまくいくようです。プロキシを使用する場合は特に良いです。


1
これは、httpclientのタイムアウトを設定する方法です。これは、httpclientがタイムアウトしたことをどのようにして知るかという問題には対処していません。
イーサンフィッシャー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.