La requête API PHP expire malgré le bon fonctionnement du point de terminaison.

1
php

<?php if (is_user_logged_in());

?>

Je tente d'effectuer une requête PHP vers une API externe, mais la requête expire périodiquement, même si le point de terminaison de l'API semble être en ligne et répondre normalement lorsque je le teste directement.

Le problème ne se produit pas à chaque requête. Certaines requêtes s'exécutent en moins d'une seconde, tandis que d'autres attendent jusqu'à l'expiration du délai.

Je cherche à déterminer si ce problème est plus susceptible d'être dû à ma configuration PHP, à l'API distante, à la latence DNS /network ou à la manière dont je traite la requête.

Code PHP actuel

php
<?php

$url = 'https://api.example.com/products';

$ch = curl_init();

curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTPHEADER => <span class="text-token-text-primary cursor-text rounded-sm" data-placeholder-token="true">[
        'Accept: application/json',
    ]</span>,
]);

$response = curl_exec($ch);

if ($response === false) {
    echo 'cURL Error: ' . curl_error($ch);
} else {
    $data = json_decode($response, true);

    echo '<pre>';
    print_r($data);
    echo '</pre>';
}

curl_close($ch);

Ce que j'ai déjà vérifié

  1. L'URL de l'API se charge correctement lors d'un test direct.
  2. cURL est activé sur le serveur.
  3. La plupart des requêtes fonctionnent
  4. L'augmentation de CURLOPT_TIMEOUT ne fait qu'allonger le temps de réponse des requêtes ayant échoué avant le retour d'une erreur.
  5. Le serveur lui-même ne semble pas présenter une utilisation anormalement élevée du processeur ou de la mémoire.
  6. Le problème se produit de manière intermittente et non à chaque requête.

Exemple d'erreur.

code
cURL error 28:
Operation timed out after 30001 milliseconds
with 0 bytes received

Ce que j'essaie de comprendre.

Quelle serait la meilleure façon de résoudre ce problème ?

Recommanderiez-vous de vérifier :

  • Le temps de résolution DNS ?
  • Le temps de connexion, indépendamment du temps total de la requête ?
  • Les en-têtes de réponse du serveur distant ?
  • Les limites PHP-FPM ?
  • Les règles de pare-feu ou de connexion sortante ?
  • La logique de nouvelle tentative ?
  • Le débit de l’API Limitation ?
  • Journalisation des informations détaillées de temps d'exécution de cURL ?

Je souhaiterais également savoir si la relance automatique de la requête est une bonne approche, ou si cela pourrait aggraver le problème si l'API distante rencontre déjà des difficultés.

Si les relances sont appropriées, quelle serait une stratégie de relance raisonnable en PHP sans provoquer de requêtes dupliquées ni de charge inutile ?

Ajout de CSS et HTML pour les tests :

css
.testt {
}
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My First Webpage</title>
</head>
<body>
  <h1>Welcome to My Webpage</h1>
  <p>Your FAce Is COde!.</p>
</body>
</html>
Your Answer

Respond directly to the original question. To respond to another answer, use Reply under that answer.

Have an answer?

Log in with your ProfoundSyntax account to participate.

Log In to Reply

2 Answers

  1. 1
    Miles Rivera
    Miles Rivera V ✓ Accepted Answer ✓ Verified Answer
    @miles-rivera 0 rep
    Replying to @diamondj
    To isolate the cause of the intermittent 28‑error you can add a few diagnostics and then decide whether a retry policy is appropriate.

    1. Collect timing data for each request

    php

       $ch = curl_init($url);
       curl_setopt_array($ch, [
           CURLOPT_RETURNTRANSFER   => true,
           CURLOPT_CONNECTTIMEOUT   => 10,
           CURLOPT_TIMEOUT          => 30,
           CURLOPT_FOLLOWLOCATION   => true,
           CURLOPT_HTTPHEADER       => ['Accept: application/json'],
       ]);
    
       $response = curl_exec($ch);
    
       if ($response === false) {
           $error = curl_error($ch);
           $info  = curl_getinfo($ch);
           error_log("cURL error: $error");
           error_log("Connect time: {$info['connect_time']}s, Total time: {$info['total_time']}s");
       } else {
           // normal handling
       }
       curl_close($ch);

    * connect_time shows DNS + TCP handshake.
    * total_time is the full round‑trip.
    * pretransfer_time can reveal TLS negotiation delays.

    Store these values in a log or a database column so you can spot patterns (e.g., spikes after a certain hour).

    2. Check DNS resolution separately

    bash

       dig api.example.com +time=5

    If the lookup sometimes takes >5 s, the DNS server is the culprit. Switch to a more reliable resolver (e.g., 8.8.8.8) or enable CURLOPT_DNS_CACHE_TIMEOUT.

    3. Verify the remote server’s health
    * Use a monitoring tool (e.g., curl -w “%{http_code} %{time_total}n” -o /dev/null -s https://api.example.com/products) to see if the endpoint itself sometimes returns 5xx or 429.
    * Look at the API provider’s status page or rate‑limit headers (X-RateLimit-Remaining, Retry-After).

    4. Inspect server‑side limits
    * PHP‑FPM workers: pm.max_children, pm.max_requests.
    * Web‑server timeouts: ProxyTimeout (Apache) or proxy_read_timeout (NGINX).
    * Firewall rules: iptables -L -n or cloud provider outbound rules.

    5. Implement a safe retry strategy
    * Only retry on idempotent verbs (GET, HEAD).
    * Use exponential back‑off with jitter:

    php

         $maxRetries = 3;
         $delay = 1; // seconds
    
         for ($i = 0; $i < $maxRetries; $i++) {
             $response = curl_exec($ch);
             if ($response !== false) break;
    
             $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
             if ($code == 429 || $code == 503) {
                 // Respect Retry-After if present
                 $retryAfter = curl_getinfo($ch, CURLINFO_HEADER_OUT);
                 // parse header if needed
             }
    
             sleep($delay + rand(0, 1)); // jitter
             $delay *= 2; // exponential
         }

    * Log each retry attempt and the reason for failure.
    * Do not retry on client errors (4xx other than 429) or on network failures that are not transient.

    6. Avoid duplicate side‑effects
    * For non‑idempotent operations (POST, PUT, DELETE) either do not retry or use a unique request ID that the API can recognize to deduplicate.

    7. Optional: use curl_multi
    If you need to send many requests concurrently, curl_multi can keep connections alive and reduce DNS lookups, but it adds complexity.

    Summary

    1. Log connect_time, total_time, and error codes.
    2. Verify DNS and remote server health.
    3. Check PHP‑FPM and web‑server timeouts.
    4. If retries are needed, limit them to idempotent calls, use exponential back‑off, and respect rate‑limit headers.

    These steps should help you pinpoint whether the problem is local, network‑wide, or on the API side, and give you a controlled way to handle transient failures.

    Verified Answer: Great Answer!

    Helpful 1
  2. 0
    Da Code Master
    Da Code Master V MOD PRO
    @derekwcodes 0 rep edited
    Replying to @diamondj

    The fact that some requests finish in under a second while others hit the 30-second timeout suggests an intermittent connection or response issue, but I wouldn't rule out PHP or the hosting environment without checking the timing data first.

    **cURL error 28 doesn't necessarily mean the API is down.** It means the operation exceeded its configured timeout. Even if the API works when tested directly, the PHP server could be experiencing DNS delays, connection problems, TLS negotiation issues, or delays waiting for a response.

    I'd start by adding detailed cURL timing diagnostics immediately after curl_exec():

    php

    $response = curl_exec($ch);
    
    $info = curl_getinfo($ch);
    
    $diagnostics = [
        'dns_time' => $info['namelookup_time'],
        'connect_time' => $info['connect_time'],
        'tls_time' => $info['appconnect_time'] ?? null,
        'first_byte_time' => $info['starttransfer_time'],
        'total_time' => $info['total_time'],
        'http_code' => $info['http_code'],
        'primary_ip' => $info['primary_ip'] ?? null,
        'curl_errno' => curl_errno($ch),
        'curl_error' => curl_error($ch)
    ];
    
    error_log(json_encode($diagnostics));

    The important part is comparing successful requests against failed ones.

    – If DNS lookup times are unusually high, investigate DNS resolution.
    – If connection establishment is slow, check outbound firewall rules, routing, IPv4/IPv6 connectivity, and hosting network restrictions.
    – If the connection completes quickly but the first response byte is delayed, investigate API-side processing, rate limits, or upstream services.
    – If the timing looks normal until a particular point, compare the affected requests and any redirects.

    I'd also test the same endpoint directly **from the server running PHP**, rather than relying solely on a browser or another computer. That can help identify differences between the two environments.

    **Regarding retries:** Yes, retries are useful for transient failures, but they should be controlled.

    For safe, read-only requests, I'd generally start with a maximum of two retries, exponential backoff, and a little random jitter. Respect the API's Retry-After header when applicable.

    Be careful with POST or other requests that modify data. A timeout doesn't guarantee the remote API failed to process the original request. Retrying could create duplicates unless the API supports idempotency keys or another deduplication mechanism.

    I also wouldn't increase CURLOPT_TIMEOUT beyond 30 seconds until the actual bottleneck is identified. A longer timeout can simply make failures take longer.

    My recommendation: Start by capturing cURL timing data for both successful and failed requests. That should narrow down whether you're dealing with DNS, connection establishment, or a remote response delay.

    One question: When the timeout happens, does it affect requests to other external APIs from the same PHP server, or only this particular endpoint? That would be useful information for isolating the problem.

    The diagnostic approach is supported by the official PHP cURL documentation: https://www.php.net/manual/en/function.curl-getinfo.php and the official cURL retry guidance: https://everything.curl.dev/usingcurl/downloads/retry.html

    Insightful 1