Le WordPress d'aujourd'hui, décodé pour les développeurs

Accessibilité

ETag et Cache-Control sur un rapport d’accessibilité JSON servi à un robot

Un script de supervision externe retélécharge un rapport d'audit à chaque exécution, même sans changement. Deux en-têtes HTTP suffisent à corriger cela.

Par WordPress Développement • 23 novembre 2022 • 5 min de lecture • Aucun commentaire
ETag et Cache-Control sur un rapport d'accessibilité JSON servi à un robot

curl -I https://exemple.fr/wp-json/wpm/v1/rapport-a11y — cette simple requête d’en-têtes révèle le problème en une ligne : ni ETag, ni Cache-Control dans la réponse. Un script de supervision externe, exécuté toutes les dix minutes pour surveiller le score d’accessibilité d’un parc de pages, retélécharge donc l’intégralité du rapport JSON à chaque passage, qu’il ait changé ou non.

Cette recette HTTP corrige le point d’entrée REST WordPress qui expose ce rapport, sans toucher à la génération du rapport lui-même : le calcul du score, les anomalies détectées et leur format restent identiques. Seule la couche de mise en cache HTTP change.

Le endpoint tel qu’il existe

Le rapport est exposé via un endpoint REST personnalisé, enregistré dans le plugin interne de l’agence :

add_action( 'rest_api_init', function () {
    register_rest_route( 'wpm/v1', '/rapport-a11y', array(
        'methods'             => 'GET',
        'callback'            => 'wpm_rest_rapport_a11y',
        'permission_callback' => '__return_true',
    ) );
} );

function wpm_rest_rapport_a11y( \WP_REST_Request $requete ) {
    $rapport = wpm_generer_rapport_a11y();
    return new \WP_REST_Response( $rapport, 200 );
}

Chaque appel recalcule et renvoie le rapport complet, sans aucune information permettant au client de savoir si le contenu a réellement changé depuis le dernier appel. Le script de supervision, de son côté, se contente d’un appel GET classique toutes les dix minutes, sans condition.

Ajouter un ETag basé sur le contenu du rapport

Un ETag est une empreinte du contenu de la réponse. Le calculer à partir d’un hachage du rapport sérialisé permet de détecter, sans regénérer quoi que ce soit côté script client, si le contenu a changé :

function wpm_rest_rapport_a11y( \WP_REST_Request $requete ) {
    $rapport = wpm_generer_rapport_a11y();
    $corps   = wp_json_encode( $rapport );
    $etag    = '"' . md5( $corps ) . '"';

    $reponse = new \WP_REST_Response( $rapport, 200 );
    $reponse->header( 'ETag', $etag );
    $reponse->header( 'Cache-Control', 'private, max-age=60, must-revalidate' );

    $etag_recu = $requete->get_header( 'if_none_match' );
    if ( $etag_recu === $etag ) {
        $reponse->set_status( 304 );
        $reponse->set_data( null );
    }

    return $reponse;
}
L'essentiel à retenir : ETag évite un retéléchargement quand rien n'a changé ; Cache-Control fixe la durée de fraîcheur côté client ; 304 Not Modified économise la bande passante et le calcul

Ce que gagne le script de supervision

Le script externe doit à présent conserver l’ETag reçu à chaque appel réussi, et le renvoyer dans l’en-tête If-None-Match de la requête suivante :

etag_precedent=$(cat /var/supervision/etag-a11y.txt 2>/dev/null)

reponse=$(curl -s -D - -o /tmp/rapport.json \
  -H "If-None-Match: ${etag_precedent}" \
  https://exemple.fr/wp-json/wpm/v1/rapport-a11y)

if echo "$reponse" | grep -q "HTTP/1.1 304"; then
  echo "Rapport inchangé, aucun traitement nécessaire."
else
  nouvel_etag=$(echo "$reponse" | grep -i '^etag:' | cut -d' ' -f2)
  echo "$nouvel_etag" > /var/supervision/etag-a11y.txt
  # traitement du nouveau rapport dans /tmp/rapport.json
fi

Quand le rapport n’a pas changé, le serveur répond 304 Not Modified avec un corps vide : le script de supervision économise la bande passante liée au transfert du JSON complet, et surtout évite de déclencher inutilement son propre traitement en aval, potentiellement coûteux si celui-ci alerte une équipe à chaque nouveau rapport reçu.

Le rôle de Cache-Control en complément

L’en-tête Cache-Control: private, max-age=60, must-revalidate ajoute une seconde couche : pendant soixante secondes après un appel, un cache HTTP intermédiaire ou le navigateur peut réutiliser la réponse sans même émettre de requête conditionnelle. La directive private signale que la réponse ne doit pas être partagée entre différents clients par un cache mutualisé, ce qui reste pertinent tant que le endpoint n’est pas strictement public au sens de la vie privée. La directive must-revalidate impose qu’une fois la fraîcheur expirée, le client revalide obligatoirement auprès du serveur plutôt que de continuer à servir une version potentiellement périmée.

Variantes selon le contexte

Pour un rapport recalculé une seule fois par heure via une tâche planifiée, plutôt qu’à chaque requête, l’ETag peut se baser directement sur l’horodatage de dernière génération plutôt que sur un hachage complet du contenu, ce qui évite de sérialiser le rapport juste pour calculer l’empreinte :

$derniere_generation = get_option( 'wpm_rapport_a11y_horodatage' );
$etag = '"' . md5( (string) $derniere_generation ) . '"';

Pour un endpoint interrogé par plusieurs scripts de supervision différents, avec des fréquences distinctes, la valeur max-age mérite d’être ajustée à la fréquence la plus courte parmi les consommateurs connus, afin qu’aucun ne reçoive une réponse mise en cache plus longtemps que ce qu’il tolère.

En résumé

Un rapport JSON destiné à un robot de supervision bénéficie exactement des mêmes mécanismes HTTP qu’une page web classique : ETag pour détecter un contenu inchangé sans le retransmettre, Cache-Control pour fixer une durée de fraîcheur raisonnable. Le gain ne se mesure pas seulement en bande passante économisée, mais aussi en charge évitée côté script consommateur, qui ne traite plus un rapport identique au précédent toutes les dix minutes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi