500, 502, 503 y 504 errores de las API: qué significan y cómo controlarlos

Un código de estado de 500 a 599 significa que el servidor no pudo completar una solicitud que parecía válida. La solicitud no es el problema, por lo que enviarla de nuevo puede funcionar. Que deba enviarlo de nuevo depende del código de estado y de lo que hace la solicitud. Para ver las definiciones, vea RFC 9110, sección 15.6.

Qué significa cada código de estado

Código de estado Qué significa ¿Reintentar?
500 Internal Server Error El servidor alcanzó una condición que no esperaba Depende de la API. Algunas API, como la API de Claude, le indican que debe reintentar tras un error 500 con retroceso exponencial. Consulte los documentos de la API.
502 Bad Gateway Una puerta de enlace o servidor proxy recibió una respuesta no válida del servidor que hay detrás de ella Sí, si la solicitud es segura para repetirse
503 Service Unavailable El servidor está temporalmente sobrecargado o inactivo por mantenimiento, y debe recuperarse después de algún tiempo. El servidor puede enviar un encabezado Retry-After. Sí, después de la Retry-After vez si el servidor envió una
504 Gateway Timeout Una puerta de enlace o proxy no recibió respuesta a tiempo del servidor que hay detrás Sí, si la solicitud es segura para repetirse. La puerta de enlace dejó de esperar, por lo que no sabe si el servidor realizó el trabajo.

Qué solicitudes son seguras para reintentar

RFC 9110 llama a un método idempotente cuando enviar la misma solicitud varias veces tiene el mismo efecto que enviarla una vez. GET, HEAD, OPTIONS, TRACE, PUTy DELETE son idempotentes. POST y PATCH no lo son. Según la RFC, un cliente no debe reintentar automáticamente una solicitud con un método no idempotente a menos que sepa que la solicitud es idempotente de todos modos, o puede determinar que el servidor nunca aplicó la solicitud original. Para obtener más información, consulte Métodos Idempotentes.

Reintentar POST después de un error 502 o 504 puede crear un segundo pedido o enviar un segundo correo electrónico. Algunas bibliotecas de reintento vuelven a intentar cada método de forma predeterminada. Por ejemplo, el controlador de resistencia estándar de .NET vuelve a intentar POST a menos que llame a options.Retry.DisableForUnsafeHttpMethods(). Para obtener más información, consulte Cree aplicaciones HTTP resistentes.

Retry-After en un 503

Un 503 puede incluir un encabezado Retry-After. Su valor es o bien un número de segundos, como 120, o bien una fecha HTTP, como Fri, 31 Dec 1999 23:59:59 GMT. El código debe manejar ambos. Para obtener más información, consulte Retry-After.

Dejar de llamar a una API que sigue fallando

Los reintentos ayudan con fallos breves. Cuando una API está inactiva durante minutos, reintentar cada solicitud agrega carga a un servidor que ya tiene problemas y los usuarios esperan a que se produzca un error en cada reintento. Un disyuntor de circuito realiza un seguimiento de los errores y, cuando hay demasiados, deja de llamar a la API durante un tiempo y falla de inmediato. Después de ese tiempo, permite que se realicen algunas solicitudes para comprobar si se recuperó la API. Para obtener más información, consulte Patrón circuit breaker. El .NET controlador estándar de resiliencia incluye un interruptor de circuito que se abre durante 5 segundos cuando al menos el 10 % de las solicitudes producen un error en una ventana de 30 segundos con al menos 100 solicitudes.

Cómo gestionar los errores 5xx

  1. Reintente los errores 502, 503 y 504 solo para solicitudes idempotentes. Para POST y PATCH, vuelva a intentarlo solo si la API documenta una manera de que se puedan repetir de forma segura.
  2. Espere antes de reintentar. Utiliza Retry-After cuando el servidor lo envíe. De lo contrario, use reintento exponencial con variación aleatoria y detenga después de algunos intentos.
  3. Lea los documentos de la API para 500. Reinténtelo solo si la API dice que es seguro.
  4. Deje de llamar a una API que sigue fallando. Use un circuit breaker para que la aplicación falle de inmediato mientras se recupera la API.
  5. Indique al usuario qué ha ocurrido. Muestra "el servicio tiene problemas, inténtelo de nuevo más tarde" en lugar de un error genérico o una traza de pila.
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));
  }
}

Cómo probar que la aplicación controla los errores 5xx

Rara vez ve un 5xx mientras desarrolla y no puede hacer que una API produzca un error a petición. La forma de probar decide si encuentras los errores antes de que los usuarios lo hagan.

Approach Lo que encuentras Lo que te pierdes
Esperar a que esté en producción Interrupciones reales Todo, hasta que un usuario haga clic en ello
Simula la API en tus pruebas o deja que tu agente de codificación escriba el mock Que se ejecute la rama de error Tu cliente HTTP real y la biblioteca de reintentos, y cuántas veces reintenta realmente. La aplicación también necesita un interruptor solo para pruebas para llegar al mock.
Llame a la API real y espere a que se produzca un error. Comportamiento real No se puede hacer que la API falle a petición
Interceptar el tráfico real de la aplicación y devolver errores 5xx con la frecuencia que elija El cliente HTTP real, la biblioteca de reintentos y el circuit breaker Nada en la aplicación cambia, por lo que no prueba el código de forma aislada. Mantenga las pruebas unitarias para eso.

Pruébalo en tu app

El proxy de desarrollo intercepta las solicitudes de la aplicación y hace que una parte de ellas falle con los errores que defina, mediante GenericRandomErrorPlugin. La aplicación sigue llamando a la dirección URL real. Agregue el complemento al archivo de configuración y apunte su errorsFile a un archivo con los errores 5xx. En este ejemplo se usa https://api.contoso.com. Reemplácelo por la dirección URL de la API a la que llama la aplicación.

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

De forma predeterminada, el complemento falla el 50 % de las solicitudes. Compruebe en la salida de Dev Proxy que su aplicación reintenta las solicitudes GET y envía cada POST una sola vez. El proxy de desarrollo no comprueba si la aplicación espera Retry-After cuando se produce un error 503, por lo que compare los tiempos de solicitud usted mismo. A continuación, inicie Dev Proxy con --failure-rate 100 para ver lo que hace la aplicación cuando la API sigue fallando. Para obtener más información, consulte Tasa de errores de solicitudes de cambio. Para instalar Dev Proxy, consulte Configurar Dev Proxy.

Pasos siguientes

Consulte también