Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Saat API terlalu lambat, aplikasi .NET Anda mendapatkan 1 dari 2 eksepsi, bergantung pada timeout mana yang terpicu.
HttpClient.Timeout melempar sebuah TaskCanceledException. Handler ketahanan standar dari Microsoft.Extensions.Http.Resilience melemparkan TimeoutRejectedException dari Polly. Mereka berasal dari tempat yang berbeda, memiliki default yang berbeda, dan membutuhkan blok terpisah catch .
Timeout mana yang terpicu
| Jeda Waktu | Default | Apa yang didapat kode Anda | Di tempat Anda menyetelnya |
|---|---|---|---|
HttpClient.Timeout |
100 detik |
TaskCanceledException, dengan TimeoutException sebagai InnerException (.NET 5 dan yang lebih baru) |
HttpClient.Timeout |
| Batas waktu upaya handler standar | 10 detik per upaya | Awalnya tidak ada respons: handler mencoba kembali upaya | AddStandardResilienceHandler(options => ...) |
| Batas waktu total untuk penangan standar | 30 detik, termasuk semua percobaan ulang | Polly.Timeout.TimeoutRejectedException |
AddStandardResilienceHandler(options => ...) |
HttpClient.Timeout
HttpClient.Timeout berlaku untuk setiap permintaan yang dikirim oleh instans HttpClient. Untuk menggunakan batas waktu yang berbeda untuk satu permintaan, teruskan CancellationToken dari CancellationTokenSource dengan batas waktunya sendiri. Yang lebih pendek dari keduanya berlaku. Setel Timeout.InfiniteTimeSpan untuk mematikannya.
Pada .NET 5 dan yang lebih baru, ketika terjadi timeout, TaskCanceledException dilempar dengan TimeoutException di dalamnya. Pada versi .NET Core yang lebih lama, tidak terdapat inner exception. Pada .NET Framework, Anda akan mendapatkan HttpRequestException sebagai gantinya. Untuk detailnya, lihat HttpClient.Timeout dan Membuat permintaan HTTP dengan kelas HttpClient.
TaskCanceledException juga berarti bahwa seseorang membatalkan permintaan, misalnya, pengguna yang menutup halaman. Untuk membedakan timeout dari pembatalan, periksa ex.InnerException is TimeoutException, atau periksa apakah token Anda sendiri telah dibatalkan.
Handler ketahanan standar
AddStandardResilienceHandler() merangkai pembatas laju, batas waktu total, coba lagi, pemutus sirkuit, dan batas waktu upaya. Ketika satu upaya membutuhkan waktu lebih dari 10 detik, batas waktu upaya membatalkannya dan strategi percobaan ulang akan mencoba kembali: hingga 3 percobaan ulang, dengan backoff eksponensial dan jitter, mulai dari 2 detik. Ketika seluruh permintaan, termasuk percobaan ulang, membutuhkan waktu lebih dari 30 detik, total batas waktu membatalkannya dan kode Anda menerima TimeoutRejectedException.
TimeoutRejectedException berasal dari Exception. Ini bukan TimeoutException maupun HttpRequestException, sehingga blok catch (HttpRequestException) tidak menangkapnya. Untuk daftar lengkap default, lihat Default handler ketahanan standar.
Misalnya, ketika aplikasi .NET 10 yang menggunakan default handler standar memanggil API yang membutuhkan waktu 11 hingga 15 detik per respons, aplikasi mendapatkan TimeoutRejectedException setelah 30 detik, dan blok catch (HttpRequestException)-nya tidak berjalan.
Cara menangani batas waktu HttpClient
- Tangkap kedua pengecualian saat Anda memanggil API. Jika Anda menggunakan handler standar, tangkap
TimeoutRejectedException. DapatkanTaskCanceledExceptionuntukHttpClient.Timeout. - Bedakan timeout dari pembatalan. Hanya memperlakukan
TaskCanceledExceptionsebagai batas waktu ketika pengecualian dalamnya adalahTimeoutException. Ketika penelepon membatalkan, berhenti diam-diam. - Pilih batas waktu yang sesuai dengan API. Jika API sering memakan waktu lebih dari 10 detik, ubah batas waktu percobaan dan total di
AddStandardResilienceHandler(options => ...). - Jangan ulangi
POSTatauPATCHkecuali API membuatnya aman. Handler standar mencoba kembali semua metode secara default, termasukPOST. Panggiloptions.Retry.DisableForUnsafeHttpMethods()untuk mengecualikanPOST,PUT,PATCH,DELETE, danCONNECT, atauoptions.Retry.DisableFor(HttpMethod.Post, HttpMethod.Patch)untuk terus mencoba kembaliPUTdanDELETEyang idempoten. - Beri tahu pengguna apa yang terjadi. Tampilkan "layanan sedang lambat, coba lagi" alih-alih kesalahan umum.
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;
}
}
Cara menguji bahwa aplikasi Anda menangani batas waktu
Anda jarang melihat timeout saat mengembangkan, sehingga blok Anda catch jarang berjalan. Cara Anda menguji memutuskan apakah Anda menemukan bug sebelum pengguna Anda melakukannya.
| Approach | Apa yang Anda temukan | Yang Anda lewatkan |
|---|---|---|
| Tunggu hingga siap produksi | Timeout sebenarnya | Semuanya, sampai pengguna mengkliknya |
| Mock API dalam pengujian Anda, atau biarkan agen coding Anda menulis mock | Apakah blok Anda catch berjalan jika tiruan melempar pengecualian yang tepat? |
Konfigurasi sebenarnya HttpClient Anda, percobaan ulang handler ketahanan, dan pengecualian yang sebenarnya dilemparkannya. Aplikasi Anda juga memerlukan sakelar khusus pengujian untuk mengakses mock. |
| Panggil API nyata dan berharap API tersebut lambat | Perilaku nyata | Anda tidak dapat membuat API lambat secara sengaja |
| Menyadap lalu lintas nyata aplikasi Anda dan menunda respons | Penangan nyata Anda, penangan ketahanan, dan pengecualian HttpClient |
Tidak ada yang berubah pada aplikasi Anda, sehingga tidak menguji kode Anda secara terisolasi. Gunakan pengujian unit untuk itu. |
Coba ini di aplikasi Anda
Dev Proxy mencegat permintaan aplikasi Anda ke API dan menunda respons dengan LatencyPlugin. .NET menggunakan proksi sistem, jadi Anda tidak perlu mengubah kode Anda. Contoh ini menunda setiap respons hingga 11 sampai 15 detik, lebih lama dari batas waktu upaya 10 detik milik handler standar. Ganti https://api.contoso.com dengan URL API yang dipanggil aplikasi Anda.
Berkas: 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
}
}
Mulai Dev Proxy dengan devproxy --config-file devproxyrc.json dan jalankan aplikasi Anda. Setiap kali upaya mengalami time-out, handler mencoba kembali, dan setelah 30 detik kode Anda mengembalikan TimeoutRejectedException. Untuk menguji HttpClient.Timeout , atur minMs lebih tinggi dari batas waktu yang Anda konfigurasikan. Untuk detail penyiapan, lihat Menggunakan Dev Proxy dengan aplikasi .NET. Untuk menginstal Dev Proxy, lihat Menyiapkan Dev Proxy.