Chyby 500, 502, 503 a 504 z rozhraní API: co znamenají a jak je zpracovat

Stavový kód od 500 do 599 znamená, že se serveru nepodařilo splnit požadavek, který vypadal jako platný. Problém není ve vašem požadavku, takže jeho opětovné odeslání může fungovat. To, jestli byste ho měli poslat znovu, závisí na stavovém kódu a na tom, co požadavek dělá. Definice naleznete v dokumentu RFC 9110, oddílu 15.6.

Význam jednotlivých stavových kódů

Stavový kód Co to znamená Zkuste to znovu?
500 Internal Server Error Server narazil na stav, který neočekával. Závisí na rozhraní API. Některá rozhraní API, jako je Claude API, vám doporučují opakovat požadavek při chybě 500 s exponenciálně se prodlužující prodlevou. Projděte si dokumentaci k rozhraní API.
502 Bad Gateway Brána nebo proxy server získaly neplatnou odpověď z navazujícího serveru Ano, pokud je požadavek bezpečný k opakování.
503 Service Unavailable Server je dočasně přetížen nebo mimo provoz a po nějaké době by se měl obnovit. Server může odeslat hlavičku Retry-After . Ano, po uplynutí doby Retry-After, pokud server nějaký odeslal
504 Gateway Timeout Brána nebo proxy server nedostaly včas odpověď od serveru, který je za ní Ano, pokud je požadavek bezpečný k opakování. Brána se vzdala čekání, takže nevíte, jestli server provedl požadovanou operaci.

Které požadavky lze bezpečně zkusit znovu

RFC 9110 označuje metodu za idempotentní, když má odeslání stejného požadavku několikrát stejný účinek jako jeho odeslání jednou. GET, HEAD, OPTIONS, TRACEPUTa DELETE jsou idempotentní. POST a PATCH nejsou. Podle RFC by klient neměl automaticky opakovat požadavek s neidempotentní metodou, pokud neví, že požadavek je stejně idempotentní, nebo může zjistit, že server původní požadavek nikdy nezpracoval. Podrobnosti najdete v tématu Idempotentní metody.

POST Opakovaný požadavek po chybě 502 nebo 504 může vytvořit druhou objednávku nebo odeslat druhý e-mail. Některé knihovny pro opakování ve výchozím nastavení opakují všechny metody. Například standardní obslužná rutina odolnosti .NET opakovaně provede POST, pokud nevoláte options.Retry.DisableForUnsafeHttpMethods(). Podrobnosti najdete v článku Vytvoření odolných aplikací HTTP.

Retry-After na 503

A 503 může obsahovat hlavičku Retry-After. Jeho hodnota je buď číselná hodnota v sekundách, například 120, nebo datum HTTP, například Fri, 31 Dec 1999 23:59:59 GMT. Váš kód musí zpracovat obojí. Podrobnosti najdete v tématu Retry-After.

Přestaňte volat rozhraní API, které stále selhává

Opakované pokusy pomáhají s krátkodobými chybami. Když je rozhraní API po dobu několika minut nedostupné, opakování každého požadavku přidává zátěž serveru, který už má potíže, a vaši uživatelé čekají, až každý opakovaný pokus selže. Circuit breaker sleduje chyby a pokud je jich příliš mnoho, přestane na chvíli volat rozhraní API a okamžitě skončí chybou. Po uplynutí této doby propustí několik požadavků, aby ověřilo, zda se rozhraní API obnovilo. Další informace naleznete v tématu vzor Circuit Breaker. Standardní obslužná rutina odolnosti v .NET zahrnuje jistič, který se otevře na 5 sekund, když v 30sekundovém intervalu selže alespoň 10 % požadavků při nejméně 100 požadavcích.

Zpracování chyb 5xx

  1. Opakujte požadavky pouze při chybách 502, 503 a 504 pro idempotentní požadavky. PATCHOpakujte POST akci pouze v případě, že rozhraní API dokumentuje způsob, jak je bezpečně opakovat.
  2. Počkejte, než to zkusíte znovu. Použijte Retry-After, když jej server odešle. V opačném případě použijte exponenciální prodlevu s náhodným zpožděním a po několika pokusech zastavte.
  3. Přečtěte si dokumentaci k rozhraní API pro verzi 500. Zkuste to znovu jenom v případě, že rozhraní API říká, že je bezpečné.
  4. Přestaňte volat rozhraní API, které selhává. Použijte circuit breaker, aby vaše aplikace selhala rychle, zatímco se rozhraní API zotavuje.
  5. Řekněte uživateli, co se stalo. Zobrazte "služba má problémy, zkuste to znovu později" místo obecné chyby nebo trasování zásobníku.
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));
  }
}

Jak otestovat, že aplikace zpracovává chyby 5xx

Při vývoji zřídka vidíte 5xx a nemůžete přimět rozhraní API, aby na požádání selhalo. Způsob, jakým testujete, určuje, zda chyby zjistíte dříve, než je najdou vaši uživatelé.

Approach Co najdete Co vám chybí
Počkejte na produkční prostředí Skutečné výpadky Všechno, dokud na to uživatel neklikne
Mockujte API v testech nebo nechte svého programovacího agenta napsat mock Jestli se spouští vaše chybová větev Váš skutečný klient HTTP a knihovna pro opakování pokusů a kolikrát skutečně provede opakování. Vaše aplikace také potřebuje testovací přepínač pro přístup k mocku.
Zavolejte skutečné rozhraní API a počkejte, až selže Skutečné chování Nemůžete přimět rozhraní API selhat na požádání
Zachyťte skutečný provoz vaší aplikace a vracejte chyby 5xx v míře, kterou zvolíte Váš skutečný klient HTTP, knihovna pro opakování požadavků a circuit breaker Ve vaší aplikaci se nic nemění, takže netestuje váš kód izolovaně. Na to si nechte jednotkové testy.

Vyzkoušejte si ji ve své aplikaci

Dev Proxy zachytí požadavky vaší aplikace a u části z nich vyvolá selhání s chybami, které definujete, pomocí modulu GenericRandomErrorPlugin. Vaše aplikace pořád volá skutečnou adresu URL. Přidejte modul plug-in do konfiguračního souboru a nasměrujte jeho errorsFile na soubor s chybami 5xx. Tento příklad používá https://api.contoso.com. Nahraďte ho adresou URL rozhraní API, které vaše aplikace volá.

Soubor: 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 }
      ]
    }
  ]
}

Ve výchozím nastavení modul plug-in selže u 50 % požadavků. Ve výstupu Dev Proxy zkontrolujte, že vaše aplikace opakuje požadavky GET a odesílá každý POST jenom jednou. Dev Proxy nekontroluje, jestli vaše aplikace při odpovědi 503 čeká na Retry-After, takže porovnejte časy požadavků sami. Potom spusťte Dev Proxy pomocí --failure-rate 100 a zjistěte, co vaše aplikace dělá, když volání API opakovaně selhává. Další informace najdete v tématu Četnost selhání žádostí o změnu. Pokud chcete nainstalovat Dev Proxy, přečtěte si téma Nastavení Dev Proxy.

Další kroky

Viz také