# Content-Encoding négocié par requête pour compresser une seule réponse GraphQL

> Compresser systématiquement chaque réponse WPGraphQL gaspille du CPU sur de petites requêtes ; ne déclencher la compression qu'au-delà d'une taille donnée change la donne.

- Auteur : WordPress Développement
- Publié le : 2022-10-07
- Mis à jour le : 2022-10-07
- Catégorie : Headless &amp; API
- URL : https://www.wpmoderne.fr/headless/content-encoding-negocie-requete-compresser-reponse-graphql/

## L’essentiel

- La compression a un coût CPU qui n'est pas toujours rentable
- Un seuil de taille évite de compresser des réponses déjà petites
- gzencode reste disponible nativement sans extension supplémentaire

Compresser systématiquement chaque réponse d'un serveur GraphQL, quelle que soit sa taille, part d'une bonne intention mais produit parfois l'effet inverse de celui recherché : sur une réponse déjà minuscule, le coût CPU de la compression peut dépasser le gain de bande passante obtenu, surtout si le serveur applique un niveau de compression élevé par défaut.

## Le problème observé

Sur un projet exposant WPGraphQL derrière un serveur PHP-FPM sans compression gérée directement par un CDN, l'activation de la compression Gzip au niveau applicatif, pour toutes les réponses sans distinction, a fait apparaître un usage CPU sensiblement plus élevé sur les requêtes GraphQL les plus courtes et les plus fréquentes — typiquement des requêtes de vérification d'état ou des requêtes très ciblées ne renvoyant que quelques champs. Ces requêtes, déjà légères en poids, n'avaient presque rien à gagner d'une compression, tout en payant intégralement son coût de calcul.

## La logique retenue : un seuil de taille

> L'essentiel à retenir : La compression a un coût CPU qui n'est pas toujours rentable ; Un seuil de taille évite de compresser des réponses déjà petites ; gzencode reste disponible nativement sans extension supplémentaire

```
// Démarre la mise en tampon dès que la requête cible l'endpoint /graphql,
// avant que WPGraphQL ne commence à écrire sa réponse.
add_action( 'init', function () {
    if ( false !== strpos( $_SERVER['REQUEST_URI'] ?? '', '/graphql' ) ) {
        ob_start();
    }
} );

add_action( 'shutdown', function () {
    if ( ! ob_get_level() ) {
        return;
    }

    $contenu = ob_get_clean();
    $accepte_gzip = isset( $_SERVER['HTTP_ACCEPT_ENCODING'] )
        && false !== strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' );

    if ( $accepte_gzip && strlen( $contenu ) > 4096 ) {
        header( 'Content-Encoding: gzip' );
        echo gzencode( $contenu, 6 );
    } else {
        echo $contenu;
    }
}, 0 );
```

Ce mécanisme s'appuie sur la mise en tampon de sortie native de PHP, disponible sans aucune extension supplémentaire, et sur `gzencode()`, également native via l'extension zlib presque systématiquement activée sur les hébergements PHP courants. Le seuil de 4 kilo-octets a été choisi empiriquement sur ce projet, après avoir observé la distribution réelle des tailles de réponses GraphQL sur plusieurs jours de trafic : la grande majorité des requêtes courtes restaient sous ce seuil, tandis que les requêtes imbriquées les plus coûteuses le dépassaient largement.

## Ce que ce mécanisme évite

- Compresser une réponse de quelques centaines d'octets pour un gain de transfert négligeable
- Appliquer un niveau de compression élevé à toutes les réponses sans distinction de taille
- Dépendre uniquement de la configuration du serveur web pour ce comportement, ce qui le rend portable d'un environnement d'hébergement à un autre

## Vérifier le comportement obtenu

```
curl -s -H "Accept-Encoding: gzip" -o /dev/null -w "%{size_download}\n" \
  https://exemple.test/graphql -d '{"query":"{ posts { nodes { id } } } "}'
```

Comparer la taille annoncée par cette commande, avec et sans l'en-tête `Accept-Encoding`, permet de confirmer que la compression ne s'active bien qu'au-delà du seuil fixé, et que les réponses courtes restent transmises telles quelles, sans en-tête `Content-Encoding` superflu.

## Une limite à connaître

Cette approche suppose de désactiver la compression gérée automatiquement par le serveur web ou par un éventuel module PHP de compression de sortie, sous peine de compresser deux fois la même réponse ou de provoquer des en-têtes contradictoires. Sur un projet où un CDN gère déjà la compression en frontal, ce mécanisme applicatif devient redondant, voire contre-productif : mieux vaut alors s'appuyer sur les règles de seuil que propose directement ce CDN plutôt que de dupliquer la logique côté PHP.

## En résumé

Compresser une réponse GraphQL n'est pas systématiquement rentable : en dessous d'une certaine taille, le coût CPU dépasse le gain de transfert. Introduire un seuil simple avant de déclencher la compression, appuyé sur la mise en tampon native de PHP et sur `gzencode()`, permet de réserver cet effort aux réponses qui en tirent réellement profit, sans sacrifier les requêtes courtes et fréquentes qui composent souvent l'essentiel du trafic d'une API GraphQL.
