Serveur web optimisé : accélérer sans changer d’hébergeur
Découvrez comment améliorer la vitesse site, les core web vitals et le temps de chargement sans changer d’hébergement.
Découvrez comment créer une API REST performante pour une application web grâce à une architecture backend optimisée et sécurisée.
Une API REST lente l’est rarement à cause du langage ou du serveur. Elle l’est à cause de quelques décisions de conception prises au début et devenues impossibles à corriger ensuite : la façon de paginer, la granularité des réponses, et l’absence de cache. Voici ces décisions, avec les codes et les en-têtes qui les mettent en œuvre, et les erreurs qui se paient le plus cher.
Choisir un verbe HTTP n’est pas une convention de style : chacun promet un comportement dont dépendent les caches, les serveurs mandataires et les mécanismes de réessai.
| Verbe | Modifie les données | Rejouable sans effet supplémentaire |
|---|---|---|
| GET | Non | Oui |
| PUT | Oui | Oui |
| DELETE | Oui | Oui |
| POST | Oui | Non |
La dernière ligne est la source d’incidents les plus courante. Un client dont la connexion coupe après l’envoi mais avant la réponse ne sait pas si l’opération a eu lieu. S’il réessaie, il crée un doublon : commande passée deux fois, paiement enregistré deux fois.
La parade tient en une ligne : acceptez une clé d’idempotence fournie par le client dans un en-tête. Vous mémorisez la réponse associée à cette clé, et un second envoi portant la même clé renvoie la première réponse au lieu de recommencer. C’est indispensable dès qu’une opération a une conséquence financière.
Les deux codes systématiquement confondus sont le 401 et le 403. Le premier signifie « je ne sais pas qui vous êtes », et invite donc à s’authentifier. Le second signifie « je sais qui vous êtes, et vous n’avez pas le droit ». Répondre 401 à un utilisateur authentifié le pousse à se reconnecter en boucle sans jamais comprendre.
Presque toutes les interfaces paginent par numéro de page. C’est simple, c’est intuitif, et c’est faux dès que les données bougent.
Pendant qu’un client parcourt les pages, des éléments sont ajoutés ou supprimés. Le décalage fait glisser les résultats : certains apparaissent deux fois, d’autres ne sont jamais lus. Sur un traitement par lots, cela produit des oublis silencieux, découverts des mois plus tard.
La pagination par curseur corrige le problème : au lieu de demander « la page 12 », le client demande « ce qui vient après cet élément ». Les insertions et suppressions n’affectent plus le parcours. Le coût est une contrainte, on ne peut plus sauter directement à une page arbitraire, et c’est presque toujours acceptable.
Deuxième règle, non négociable : plafonnez la taille de page côté serveur. Une interface qui accepte une limite fournie par le client accepte aussi qu’on lui demande cent mille éléments d’un coup, et c’est le moyen le plus simple de la faire tomber.
Une liste de cent éléments, et pour chacun une requête supplémentaire en base pour aller chercher son auteur ou sa catégorie. L’interface exécute alors cent une requêtes là où deux suffiraient.
C’est de loin la première cause de lenteur d’une interface, et elle est invisible en développement où la base contient dix lignes. Elle n’apparaît qu’en production, où elle s’aggrave proportionnellement au succès.
Le remède est de charger les données liées en une seule requête groupée. Le diagnostic, lui, passe par le comptage des requêtes exécutées par appel : c’est la mesure à afficher en développement, bien avant le temps de réponse. Les mêmes principes s’appliquent à un site, comme nous le détaillons dans notre article sur l’optimisation des performances sans changer d’hébergement.
Une interface qui recalcule à chaque appel une réponse qui n’a pas changé gaspille la ressource la plus chère dont elle dispose.
ETag: "a1b2c3" If-None-Match: "a1b2c3" -> 304 Not Modified
Le serveur joint une empreinte à chaque réponse. Au rappel suivant, le client la renvoie ; si rien n’a changé, le serveur répond par un code de non-modification, sans corps. Le gain porte à la fois sur le calcul et sur les données transférées, et il est considérable sur une application mobile.
Cette empreinte sert aussi à éviter l’écrasement concurrent : un client qui modifie une ressource peut préciser l’empreinte dont il dispose, et le serveur refuse si elle a changé entre-temps.
Sur la sécurité, enfin, une interface est un service exposé comme un autre : authentification solide, chiffrement du transport, validation stricte des entrées. Les mesures sont celles décrites dans notre article sur la sécurité d’un serveur, et un pare-feu ne les remplacera pas, comme le rappelle notre article sur le rôle des pare-feu.
Le style REST convient très bien à des ressources identifiables que l’on lit et que l’on modifie. Il convient mal à deux cas fréquents, et s’entêter coûte cher.
Le premier est celui des clients qui ont chacun besoin d’un assemblage différent de données : ils multiplient les appels ou reçoivent bien plus que nécessaire. Une application mobile et un tableau de bord interne n’ont presque jamais les mêmes besoins sur les mêmes ressources.
Le second est celui des échanges continus, notification en temps réel ou flux d’événements, pour lesquels interroger en boucle gaspille des ressources des deux côtés et introduit toujours un retard. D’autres approches existent pour ces situations, et rien n’interdit de les mélanger dans une même application : une interface REST pour les ressources, un canal dédié pour les événements.
Le 401 signifie que le client n’est pas authentifié et doit fournir des identifiants. Le 403 signifie qu’il est identifié mais n’a pas le droit d’accéder à la ressource. Répondre 401 à un utilisateur authentifié le fait se reconnecter en boucle.
En acceptant une clé d’idempotence fournie par le client dans un en-tête. Le serveur mémorise la réponse associée et renvoie la même en cas de second envoi, ce qui évite qu’une coupure réseau ne provoque une double commande.
Par curseur dès que les données évoluent. Avec une pagination par numéro de page, les ajouts et suppressions font glisser les résultats : certains éléments apparaissent deux fois et d’autres ne sont jamais lus.
Les requêtes en base répétées pour chaque élément d’une liste. Cent éléments peuvent déclencher cent une requêtes au lieu de deux. Le défaut est invisible en développement et s’aggrave proportionnellement au succès.
À éviter de renvoyer une réponse inchangée. Le serveur joint une empreinte, le client la renvoie au rappel suivant, et si rien n’a changé le serveur répond sans corps. La même empreinte sert à refuser une modification concurrente.
Découvrez comment améliorer la vitesse site, les core web vitals et le temps de chargement sans changer d’hébergement.
Une fois décidé de confier votre site à l’extérieur, reste la question difficile : quelle agence web choisir.…
« Pourquoi faire appel à une agence web plutôt que de le faire en interne ? » La…