# 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.

- Auteur : WordPress Développement
- Publié le : 2022-11-23
- Mis à jour le : 2022-11-23
- Catégorie : Accessibilité
- URL : https://www.wpmoderne.fr/accessibilite/etag-cache-control-rapport-accessibilite-json/

## L’essentiel

- 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

`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.
