Erreurs 500, 502, 503 et 504 provenant d’API : ce que signifient les erreurs 500, 502, 503 et 504 et comment les gérer

Un code d’état de 500 à 599 signifie que le serveur n’a pas pu répondre à une demande qui semblait valide. Votre demande n’est pas le problème, donc l’envoyer à nouveau peut fonctionner. La décision de renvoyer une requête dépend du code d’état et de la nature de l’opération demandée. Pour connaître les définitions, consultez RFC 9110, section 15.6.

Signification de chaque code d’état

Code de statut Ce que cela signifie Nouvelle tentative ?
500 Internal Server Error Le serveur a atteint une condition qu’il n’attendait pas Cela dépend de l’API. Certaines API, comme l’API Claude, recommandent de réessayer après une erreur 500 en appliquant un backoff exponentiel. Consultez les documents de l’API.
502 Bad Gateway Une passerelle ou un proxy a obtenu une réponse non valide du serveur derrière celui-ci Oui, si la requête peut être répétée sans risque
503 Service Unavailable Le serveur est temporairement surchargé ou arrêté pour maintenance, et il devrait redevenir accessible après un certain temps. Le serveur peut envoyer un en-tête Retry-After. Oui, après le délai Retry-After si le serveur en a indiqué un
504 Gateway Timeout Une passerelle ou un proxy n’a pas reçu de réponse à temps du serveur situé en amont Oui, si la demande peut être répétée sans risque. La passerelle a cessé d’attendre. Vous ne savez donc pas si le serveur a effectué le travail.

Quelles requêtes sont sécurisées pour réessayer

La RFC 9110 considère qu’une méthode est idempotente lorsque l’envoi de la même requête plusieurs fois a le même effet que son envoi une seule fois. GET, HEAD, TRACE, OPTIONS, PUT et DELETE sont idempotents. POST et PATCH ne le sont pas. Selon la RFC, un client ne doit pas réessayer automatiquement une demande avec une méthode non idempotente, sauf s’il sait que la requête est idempotente de toute façon, ou qu’il peut déterminer que le serveur n’a jamais appliqué la requête d’origine. Pour plus d’informations, consultez les méthodes idempotentes.

Une nouvelle tentative POST après un 502 ou 504 peut créer une deuxième commande ou envoyer un deuxième e-mail. Certaines bibliothèques de nouvelle tentative réessaient toutes les méthodes par défaut. Par exemple, le gestionnaire de résilience standard .NET réessayePOST, sauf si vous appelez options.Retry.DisableForUnsafeHttpMethods(). Pour plus d’informations, consultez Créer des applications HTTP résilientes.

Retry-After dans une réponse 503

Un 503 peut inclure un en-tête Retry-After. Sa valeur est soit un nombre de secondes, par 120exemple, soit une date HTTP, comme Fri, 31 Dec 1999 23:59:59 GMT. Votre code doit gérer les deux. Pour plus d’informations, consultez Retry-After.

Arrêter l’appel d’une API qui continue d’échouer

Les réessais aident en cas d’échecs temporaires. Lorsqu’une API est en panne pendant des minutes, réessayer chaque requête ajoute une charge à un serveur déjà en difficulté, et vos utilisateurs attendent que chaque nouvelle tentative échoue. Un disjoncteur suit les échecs et, lorsqu’ils sont trop nombreux, cesse temporairement d’appeler l’API et échoue rapidement. Après ce temps, il laisse passer quelques requêtes pour vérifier si l’API s’est rétablie. Pour plus d’informations, consultez le modèle Circuit Breaker. Le gestionnaire de résilience standard de .NET comprend un disjoncteur qui s’ouvre pendant 5 secondes lorsque, sur une période de 30 secondes comptant au moins 100 requêtes, au moins 10 % des requêtes échouent.

Comment gérer les erreurs 5xx

  1. Réessayez les requêtes idempotentes uniquement en cas de code 502, 503 ou 504. Pour POST et PATCH, réessayez uniquement si l’API documente un moyen de garantir qu’ils peuvent être relancés sans risque.
  2. Attendez avant de réessayer. Utilisez Retry-After quand le serveur l’envoie. Sinon, utilisez un backoff exponentiel avec une gigue aléatoire et arrêtez après quelques tentatives.
  3. Consultez la documentation de l’API concernant les erreurs 500. Réessayez uniquement si l’API indique que cela est sans danger.
  4. Arrêtez d’appeler une API qui échoue constamment. Utilisez un disjoncteur pour que votre application échoue rapidement pendant que l’API se rétablit.
  5. Indiquez à l’utilisateur ce qui s’est passé. Affichez « le service rencontre des problèmes, réessayez ultérieurement » au lieu d’une erreur générique ou d’une trace de pile.
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));
  }
}

Comment tester que votre application gère les erreurs 5xx

Vous voyez rarement un 5xx pendant que vous développez, et vous ne pouvez pas provoquer l’échec d’une API à la demande. La façon dont vous testez détermine si vous trouvez les bogues avant que vos utilisateurs ne le fassent.

Approach Ce que vous trouvez Ce qui vous manque
Attendre la mise en production Pannes réelles Tout, jusqu’à ce qu’un utilisateur y soit confronté
Simuler l’API dans vos tests ou laisser votre agent de codage écrire la simulation Si votre branche d’erreur s’exécute Votre client HTTP réel et votre bibliothèque de nouvelles tentatives, et combien de fois il retente réellement. Votre application a également besoin d’un commutateur réservé aux tests pour accéder au simulateur.
Appelez l’API réelle et attendez qu’elle échoue Comportement réel Vous ne pouvez pas faire échouer l’API volontairement
Interceptez le trafic réel de votre application et retournez des erreurs 5xx à un débit que vous choisissez Votre client HTTP réel, votre bibliothèque de nouvelle tentative et votre disjoncteur. Rien dans votre application ne change, de sorte que cela ne teste pas votre code de manière isolée. Conservez vos tests unitaires pour cela.

Essayez-le dans votre application

Dev Proxy intercepte les requêtes de votre application et fait échouer une partie d’entre elles avec les erreurs que vous définissez, à l’aide du plug-in GenericRandomErrorPlugin. Votre application continue d’appeler l’URL réelle. Ajoutez le plug-in à votre fichier de configuration et faites pointer son errorsFile vers un fichier contenant les erreurs 5xx. Cet exemple utilise https://api.contoso.com. Remplacez-le par l’URL de l’API que votre application appelle.

Fichier : server-errors.json

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

Par défaut, le plug-in fait échouer 50 % des requêtes. Vérifiez dans la sortie de Dev Proxy que votre application retente les requêtes GET et n’envoie chaque POST qu’une seule fois. La valeur @dynamic=10 définit Retry-After sur 10 secondes. Pour que Dev Proxy signale lorsque votre application appelle à nouveau l’API avant l’expiration de ce délai, ajoutez le RetryAfterPlugin avant le GenericRandomErrorPlugin dans votre fichier de configuration. Démarrez ensuite Dev Proxy avec --failure-rate 100 pour voir ce que fait votre application lorsque l’API continue d’échouer. Pour plus d’informations, consultez Le taux d’échec des demandes de modification. Pour installer Dev Proxy, consultez Configurer Dev Proxy.

Étapes suivantes

Voir aussi