Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Pokud je rozhraní API příliš pomalé, aplikace .NET získá 1 ze 2 výjimek v závislosti na tom, který časový limit se aktivoval.
HttpClient.Timeout vyvolá TaskCanceledException. Standardní obslužná rutina odolnosti z Microsoft.Extensions.Http.Resilience vyvolá TimeoutRejectedException z Polly. Pocházejí z různých míst, mají různé výchozí hodnoty a potřebují samostatné catch bloky.
Který časový limit vypršel
| Přerušení zápasu | Výchozí | Co váš kód obdrží | Kde ho nastavíte |
|---|---|---|---|
HttpClient.Timeout |
100 sekund |
TaskCanceledException, s TimeoutException jako InnerException (.NET 5 a novější) |
HttpClient.Timeout |
| Standardní časový limit pro pokus obslužné rutiny | 10 sekund za pokus | Zpočátku nic: obslužná rutina pokus opakuje. | AddStandardResilienceHandler(options => ...) |
| Celkový časový limit standardního handleru | 30 sekund včetně všech opakování | Polly.Timeout.TimeoutRejectedException |
AddStandardResilienceHandler(options => ...) |
HttpClient.Timeout
HttpClient.Timeout platí pro každý požadavek, který odešle instance HttpClient. Pokud chcete pro jeden požadavek použít jiný časový limit, předejte CancellationToken z CancellationTokenSource s vlastním časovým limitem. Kratší z těchto dvou možností platí. Nastavte Timeout.InfiniteTimeSpan na vypnuto.
V .NET 5 a novějších časový limit vyvolá TaskCanceledException s vnitřní výjimkou TimeoutException. V dřívějších verzích .NET Core vnitřní výjimka není k dispozici. V rozhraní .NET Framework místo toho získáte HttpRequestException. Podrobnosti najdete v tématu HttpClient.Timeout a provádění požadavků HTTP pomocí třídy HttpClient.
A TaskCanceledException také znamená, že někdo žádost zrušil, například uživatel, který stránku zavřel. Pokud chcete rozlišit časový limit od zrušení, zkontrolujte ex.InnerException is TimeoutException nebo zkontrolujte, zda byl váš vlastní token zrušen.
Standardní zpracování odolnosti
AddStandardResilienceHandler() zřetězuje omezovač rychlosti požadavků, celkový časový limit, opakování, circuit breaker a časový limit pokusu. Pokud jeden pokus trvá déle než 10 sekund, časový limit pokusu ho zruší a strategie opakování se pokusí znovu: až 3 opakování s exponenciálním zpoždováním a náhodným rozptylem, počínaje 2 sekundami. Pokud celý požadavek, včetně opakování, trvá déle než 30 sekund, celkový časový limit ho zruší a vašemu kódu se vrátí TimeoutRejectedException.
TimeoutRejectedException je odvozeno z Exception. Není to ani TimeoutException, ani HttpRequestException, takže ho blok catch (HttpRequestException) nezachytí. Úplný seznam výchozích hodnot najdete v tématu Standardní výchozí hodnoty obslužné rutiny pro zajištění odolnosti.
Když například aplikace .NET 10, která používá výchozí nastavení standardní obslužné rutiny, volá rozhraní API, které trvá 11 až 15 sekund na odpověď, aplikace po 30 sekundách obdrží TimeoutRejectedException a její catch (HttpRequestException) blok se nespustí.
Jak řešit časové limity HttpClient
- Zachyťte obě výjimky tam, kde voláte rozhraní API. Pokud používáte standardní obslužnou proceduru, použijte
TimeoutRejectedException. ZachytitTaskCanceledExceptionproHttpClient.Timeout. - Rozlišit vypršení časového limitu od zrušení Za časový limit považujte
TaskCanceledExceptionpouze tehdy, když je jeho vnitřní výjimkouTimeoutException. Když volající zruší, tiše zastavte. - Vyberte časové limity, které odpovídají rozhraní API. Pokud odpověď API často trvá déle než 10 sekund, změňte časový limit pokusu a celkový časový limit v
AddStandardResilienceHandler(options => ...). - Neopakujte
POSTaniPATCH, pokud to rozhraní API neoznačí jako bezpečné. Standardní obslužná rutina ve výchozím nastavení opakuje všechny metody, včetněPOST. Zavolejteoptions.Retry.DisableForUnsafeHttpMethods(), chcete-li vyloučitPOST,PATCH,DELETE,PUTaCONNECT, nebo zavolejteoptions.Retry.DisableFor(HttpMethod.Post, HttpMethod.Patch), chcete-li pokračovat v opakování idempotentníchPUTaDELETE. - Řekněte uživateli, co se stalo. Místo obecné chyby zobrazte "služba je pomalá, zkuste to znovu".
using Polly.Timeout;
public async Task<string?> GetForecastAsync(HttpClient client, CancellationToken cancellationToken)
{
try
{
return await client.GetStringAsync("https://api.contoso.com/forecast", cancellationToken);
}
catch (TimeoutRejectedException)
{
// Standard resilience handler: total timeout expired after all retries
return null;
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
// HttpClient.Timeout expired
return null;
}
catch (HttpRequestException)
{
// Network error, or an error status code after all retries
return null;
}
}
Jak otestovat, že aplikace zvládá timeouty
Při vývoji se vypršení časového limitu zřídka objeví, takže se vaše bloky catch zřídka spouštějí. Způsob, jakým testujete, rozhoduje o tom, jestli chyby zjistíte dříve, než je najdou vaši uživatelé.
| Approach | Co najdete | Co vám chybí |
|---|---|---|
| Počkejte na produkci | Skutečné časové limity | Všechno, dokud na něj uživatel neklikne |
| V testech mockujte API nebo nechte agenta pro psaní kódu napsat mock | Zda se váš blok catch spustí, když mock vyvolá správnou výjimku |
Vaše skutečné HttpClient nastavení, opakované pokusy handleru odolnosti a výjimka, kterou skutečně vyvolá. Vaše aplikace také potřebuje testovací přepínač pro přístup k mocku. |
| Zavolejte skutečné rozhraní API a doufejte, že je pomalé | Skutečné chování | Rozhraní API nejde na vyžádání zpomalit. |
| Zachyťte skutečný provoz aplikace a zpozděte odpovědi | Vaše skutečná HttpClientobslužná rutina pro zajištění odolnosti a výjimky |
V aplikaci se nic nemění, takže netestuje váš kód izolovaně. Na to si nechte jednotkové testy. |
Vyzkoušejte si ji v aplikaci
Dev Proxy zachytává požadavky vaší aplikace na rozhraní API a zpožďuje odpovědi s LatencyPlugin. .NET používá systémový proxy server, takže kód nemusíte měnit. Tento příklad zpožďuje každou odpověď o 11 až 15 sekund, což je déle než standardní 10sekundový časový limit pokusu. Nahraďte https://api.contoso.com adresou URL rozhraní API, které vaše aplikace volá.
Soubor: devproxyrc.json
{
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/rc.schema.json",
"plugins": [
{
"name": "LatencyPlugin",
"enabled": true,
"pluginPath": "~appFolder/plugins/DevProxy.Plugins.dll",
"configSection": "slowApi"
}
],
"urlsToWatch": [
"https://api.contoso.com/*"
],
"slowApi": {
"$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/latencyplugin.schema.json",
"minMs": 11000,
"maxMs": 15000
}
}
Spusťte Dev Proxy pomocí devproxy --config-file devproxyrc.json a spusťte aplikaci. U každého pokusu dojde k vypršení časového limitu, handler to zkusí znovu a po 30 sekundách je vašemu kódu vráceno TimeoutRejectedException. Pokud chcete místo toho testovat HttpClient.Timeout , nastavte minMs vyšší než časový limit, který jste nakonfigurovali. Podrobnosti o nastavení najdete v tématu Použití Dev Proxy s aplikacemi .NET. Pokud chcete nainstalovat Dev Proxy, přečtěte si téma Nastavení Dev Proxy.