API'lerden 500, 502, 503 ve 504 hataları: ne anlama geldikleri ve bunların nasıl ele alınacağı

500 ile 599 arasındaki durum kodu, sunucunun geçerli görünen bir isteği yerine getiremediği anlamına gelir. Sorun isteğiniz olmadığından yeniden göndermek işe yarayabiliyor. Yeniden göndermeniz gerekip gerekmediği durum koduna ve isteğin ne yaptığına bağlıdır. Tanımlar için bkz. RFC 9110, bölüm 15.6.

Her durum kodunun anlamı

Durum kodu Ne anlama gelir? Yeniden denensin mi?
500 Internal Server Error Sunucu beklenmeyen bir durumla karşılaştı API'ye bağlıdır. Claude API gibi bazı API'ler, 500 hatasında üstel geri çekilme ile yeniden denemenizi söyler. API'nin belgelerine bakın.
502 Bad Gateway Ağ geçidi veya ara sunucu, arkasındaki sunucudan geçersiz bir yanıt aldı Evet, isteğin tekrarlanması güvenliyse
503 Service Unavailable Sunucu bakım için geçici olarak aşırı yüklenmiş veya devre dışıdır ve bir süre sonra düzelmesi beklenir. Sunucu bir Retry-After üst bilgi gönderebilir. Evet, sunucu bir tane gönderdiyse Retry-After zamanından sonra
504 Gateway Timeout Ağ geçidi veya ara sunucu, arkasındaki sunucudan zamanında yanıt alamadı Evet, istek yeniden güvenle yapılabiliyorsa. Ağ geçidi beklemeyi bıraktı, bu nedenle sunucunun işi yapıp yapmadığını bilmiyorsunuz.

Hangi istekleri yeniden denemek güvenlidir?

RFC 9110, aynı isteğin birkaç kez gönderilmesinin, bir kez gönderilmesiyle aynı etkiye sahip olması durumunda bir yöntemi idempotent olarak adlandırır. GET, HEAD, OPTIONS, TRACE, PUT, ve DELETE idempotenttir. POST ve PATCH öyle değil. RFC'ye göre, istemcinin, isteğin zaten idempotent olduğunu bilmediği veya sunucunun özgün isteği hiç uygulamadığını anlayamadığı sürece, bir isteği idempotent olmayan bir yöntemle otomatik olarak yeniden denememesi gerekir. Ayrıntılar için bkz. Idempotent yöntemleri.

502 veya 504 sonrasında POST yeniden denendiğinde ikinci bir sipariş oluşturabilir veya ikinci bir e-posta gönderebilir. Bazı yeniden deneme kitaplıkları varsayılan olarak her yöntemi yeniden dener. Örneğin, .NET standart dayanıklılık işleyicisi, POST çağırmadığınız sürece yeniden dener. Ayrıntılar için bkz. Dayanıklı HTTP uygulamaları oluşturma.

503'te Retry-After

503, bir Retry-After başlık içerebilir. Değeri, 120 gibi bir saniye sayısı veya Fri, 31 Dec 1999 23:59:59 GMT gibi bir HTTP tarihidir. Kodunuzun ikisini de işlemesi gerekir. Ayrıntılar için bkz. Retry-After.

Başarısız olan bir API'yi çağırmayı bırakın

Yeniden denemeler geçici hatalarda yardımcı olur. Bir API dakikalarca çalışmadığında, her isteğin yeniden denenmesi zaten zor durumda olan bir sunucuya yük ekler ve kullanıcılarınız her yeniden denemenin başarısız olmasını bekler. Devre kesici hataları izler ve çok fazla olduğunda API'yi bir süre çağırmayı durdurur ve hemen hata verir. Bu süreden sonra, API'nin kurtarılıp kurtarılmadığını denetlemek için birkaç isteğin geçmesine izin verir. Daha fazla bilgi için bkz. Devre Kesici deseni. .NET standart dayanıklılık işleyicisi, en az 100 istek içeren 30 saniyelik bir zaman aralığında isteklerin en az %10'u başarısız olduğunda 5 saniye boyunca açılan bir devre kesici içerir.

5xx hataları nasıl ele alınır

  1. Yalnızca idempotent istekler için 502, 503 ve 504'i yeniden deneyin. PATCH ve POST için, yalnızca API bunların güvenle tekrarlanmasını sağlayan bir yolu belgelediyse yeniden deneyin.
  2. Yeniden denemeden önce bekleyin. Sunucu gönderdiğinde kullanın Retry-After . Aksi takdirde, rastgele jitter ile üstel geri çekilme stratejisi kullanın ve birkaç denemeden sonra durun.
  3. 500 için API'nin belgelerini okuyun. Yalnızca API güvenli olduğunu söylüyorsa yeniden deneyin.
  4. Başarısız olan bir API'yi çağırmayı durdurun. API toparlanırken uygulamanızın hızlı bir şekilde başarısız olması için bir devre kesici kullanın.
  5. Kullanıcıya ne olduğunu anlatın. Genel bir hata veya yığın izlemesi yerine "hizmet sorun yaşıyor, daha sonra yeniden deneyin" ifadesini gösterin.
const RETRYABLE_STATUS = new Set([502, 503, 504]);
const IDEMPOTENT_METHODS = new Set(["GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"]);

function retryAfterMs(response) {
  const value = response.headers.get("retry-after");
  if (!value) return null;
  const seconds = Number(value);
  if (Number.isFinite(seconds)) return seconds * 1000;
  const date = Date.parse(value);
  return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
}

export async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  const method = (options.method ?? "GET").toUpperCase();
  const canRetry = IDEMPOTENT_METHODS.has(method);

  for (let attempt = 0; ; attempt++) {
    const response = await fetch(url, options);
    if (!RETRYABLE_STATUS.has(response.status) || !canRetry || attempt === maxRetries) {
      return response;
    }
    await response.body?.cancel();
    const backoff = 2 ** attempt * 1000 + Math.random() * 1000;
    const wait = retryAfterMs(response) ?? backoff;
    await new Promise((resolve) => setTimeout(resolve, wait));
  }
}

Uygulamanızın 5xx hatalarını işlemesini test etme

Geliştirirken nadiren 5xx görürsünüz ve api'nin isteğe bağlı olarak başarısız olmasına neden olamazsınız. Test yönteminiz, hataları kullanıcılarınızdan önce bulup bulamayacağınızı belirler.

Approach Bulduklarınız Kaçırdıklarınız
Üretimi bekleyin Gerçekleşen kesintiler Bir kullanıcı ona tıklayana kadar her şey
Testlerinizde API'yi taklit edin veya kodlama aracınızın mock’u yazmasına izin verin Hata dalınızın çalışıp çalışmadığını Gerçek HTTP istemciniz, yeniden deneme kitaplığınız ve gerçekte kaç kez yeniden denediği Uygulamanızın da mock ortama erişmek için yalnızca test amaçlı bir anahtara ihtiyacı vardır.
Gerçek API'yi çağırın ve başarısız olmasını bekleyin Gerçek davranış API'nin istediğinizde başarısız olmasına neden olamazsınız
Uygulamanızın gerçek trafiğini yakalayın ve seçtiğiniz oranda 5xx hataları döndürün Gerçek HTTP istemciniz, yeniden deneme kitaplığınız ve devre kesiciniz Uygulamanızda hiçbir şey değişmez, bu nedenle kodunuzu yalıtılmış olarak test etmez. Bunun için birim testlerinizi kullanın.

Uygulamanızda deneyin

Dev Proxy, GenericRandomErrorPlugin kullanarak uygulamanızın isteklerini yakalar ve bunların bir kısmını tanımladığınız hatalarla başarısız kılar. Uygulamanız gerçek URL'yi çağırmaya devam ediyor. Eklentiyi yapılandırma dosyanıza ekleyin ve onun errorsFile öğesini 5xx hataları içeren bir dosyaya yönlendirin. Bu örnekte https://api.contoso.com kullanılmıştır. Bunu uygulamanızın çağırdığı API'nin URL'si ile değiştirin.

Dosya: server-errors.json

{
  "$schema": "https://raw.githubusercontent.com/dotnet/dev-proxy/main/schemas/v3.3.1/genericrandomerrorplugin.errorsfile.schema.json",
  "errors": [
    {
      "request": {
        "url": "https://api.contoso.com/*"
      },
      "responses": [
        { "statusCode": 500 },
        { "statusCode": 502 },
        {
          "statusCode": 503,
          "headers": [
            { "name": "Retry-After", "value": "10" }
          ]
        },
        { "statusCode": 504 }
      ]
    }
  ]
}

Varsayılan olarak, eklenti isteklerin %50’sinde başarısız olur. Uygulamanızın GET isteklerini yeniden denediğini ve her POST isteğini yalnızca bir kez gönderdiğini Dev Proxy çıkışında denetleyin. Dev Proxy, uygulamanızın 503 durumunda Retry-After bekleyip beklemediğini kontrol etmez, bu nedenle istek sürelerini kendiniz karşılaştırın. Ardından API sürekli başarısız olurken uygulamanızın ne yaptığını görmek için --failure-rate 100 ile Dev Proxy'yi başlatın. Daha fazla bilgi için bkz. Değişiklik isteği başarısızlık oranı. Dev Proxy'yi yüklemek için bkz. Dev Proxy'yi ayarlama.

Sonraki Adımlar

Ayrıca bkz.