7 min

Filtrage côté serveur vs côté client : une checklist de décision

Checklist filtrage côté serveur vs côté client selon taille des données, latence, permissions et cache, pour éviter fuites UI et lenteurs.

Filtrage côté serveur vs côté client : une checklist de décision

Le vrai problème : fuites, lenteur et incohérences

Le filtrage dans une interface est plus qu'une simple barre de recherche. Il inclut souvent plusieurs actions liées qui changent ce que l'utilisateur voit : recherche textuelle (nom, email, identifiant de commande), facettes (statut, propriétaire, plage de dates, tags) et tri (plus récent, valeur la plus élevée, dernière activité).

La question clé n'est pas quelle technique est « meilleure », mais où réside l'ensemble de données complet et qui y a accès. Si le navigateur reçoit des enregistrements que l'utilisateur ne devrait pas voir, l'UI peut exposer des données sensibles même si vous les cachez visuellement.

La plupart des débats sur filtrage côté serveur vs côté client réagissent en réalité à deux échecs que les utilisateurs remarquent immédiatement :

  • Fuites : des données apparaissent dans les payloads réseau, les réponses en cache, ou via des filtres inattendus qui révèlent des lignes cachées.
  • Lenteur : l'écran paraît lent parce que vous envoyez trop de données, puis faites faire un travail lourd à l'appareil à chaque frappe.

Il y a un troisième problème qui génère des rapports de bugs sans fin : résultats incohérents. Si certains filtres s'exécutent côté client et d'autres côté serveur, les utilisateurs voient des comptes, des pages et des totaux qui ne correspondent pas. Cela brise rapidement la confiance, surtout sur les listes paginées.

Une règle pratique : si l'utilisateur n'est pas autorisé à accéder à l'ensemble complet, filtrez côté serveur. S'il est autorisé et que le jeu de données est suffisamment petit pour être chargé rapidement, le filtrage côté client peut convenir.

Définitions rapides en langage clair

Filtrer, c'est simplement « montre-moi les éléments qui correspondent ». La question est où la correspondance se fait : dans le navigateur (client) ou sur votre backend (serveur).

Filtrage côté client s'exécute dans le navigateur. L'app télécharge un ensemble d'enregistrements (souvent en JSON), puis applique les filtres localement. Cela peut sembler instantané après le chargement, mais ne fonctionne que si le jeu de données est suffisamment petit à envoyer et suffisamment sûr à exposer.

Filtrage côté serveur s'exécute sur votre backend. Le navigateur envoie les critères (par exemple status=open, owner=me, createdAfter=Jan 1) et le serveur retourne seulement les résultats correspondants. En pratique, il s'agit d'un endpoint API qui accepte des filtres, construit une requête base de données et renvoie une liste paginée avec des totaux.

Un modèle mental simple :

  • Côté client : télécharger beaucoup, filtrer ici.
  • Côté serveur : demander exactement ce dont vous avez besoin.

Les architectures hybrides sont courantes. Un bon schéma consiste à faire appliquer les gros filtres côté serveur (permissions, appartenance, plage de dates, recherche), puis à utiliser de petits bascules UI localement (cacher les archivés, chips de tags rapides, visibilité de colonnes) sans nouvelle requête.

Le tri, la pagination et la recherche font généralement partie de la même décision. Ils affectent la taille des payloads, la sensation utilisateur et les données exposées.

Facteur de décision 1 : taille des données et coût du payload

Commencez par la question la plus pragmatique : combien de données enverriez-vous au navigateur si vous filtriez côté client ? Si la réponse honnête est « plus que quelques écrans », vous le paierez en temps de téléchargement, en mémoire et en interactions plus lentes.

Vous n'avez pas besoin d'estimations parfaites. Obtenez juste l'ordre de grandeur : combien de lignes l'utilisateur pourrait voir, et quelle est la taille moyenne d'une ligne ? Une liste de 500 éléments avec quelques champs courts n'est pas la même chose que 50 000 éléments où chaque ligne contient de longues notes, du texte riche ou des objets imbriqués.

Les enregistrements larges sont les tueurs silencieux de payloads. Un tableau peut paraître petit en nombre de lignes mais lourd si chaque ligne contient beaucoup de champs, de longues chaînes ou des données jointes (contact + entreprise + dernière activité + adresse complète + tags). Même si vous n'affichez que trois colonnes, les équipes envoient souvent « tout, au cas où », et le payload explose.

Pensez aussi à la croissance. Un jeu de données acceptable aujourd'hui peut devenir pénible en quelques mois. Si les données croissent vite, considérez le filtrage côté client comme un raccourci à court terme, pas comme un choix par défaut.

Règles empiriques :

  • Si vous ne pouvez pas envoyer confortablement l'ensemble des données sur une connexion mobile typique, filtrez côté serveur.
  • Si les utilisateurs ne consultent qu'une petite partie à la fois, récupérez cette tranche et filtrez côté serveur.
  • Si le jeu de données est petit, stable et vraiment sûr à exposer, le filtrage côté client peut être agréable.

Ce dernier point importe pour autre chose que la performance : « Peut-on envoyer tout le jeu de données au navigateur ? » est aussi une question de sécurité. Si la réponse n'est pas un oui confiant, ne l'envoyez pas.

Facteur de décision 2 : latence et ressenti utilisateur

Les choix de filtrage échouent souvent sur le ressenti, pas sur la justesse. Les utilisateurs ne mesurent pas les millisecondes ; ils remarquent les pauses, les scintillements et les résultats qui sautent pendant qu'ils tapent.

Le temps peut se perdre à différents endroits :

  • Réseau : temps requête/réponse et taille du payload
  • Serveur : requêtes base de données, jointures, tris, vérifications de permissions
  • Navigateur : parsing du JSON, rendu des lignes, filtrage de grands tableaux

Définissez ce que « assez rapide » signifie pour cet écran. Une vue en liste peut nécessiter une saisie réactive et un défilement fluide, tandis qu'une page de rapport peut tolérer une courte attente si le premier résultat apparaît rapidement.

Ne jugez pas seulement sur le Wi‑Fi du bureau. Sur des connexions lentes, le filtrage côté client peut paraître agréable après le premier chargement, mais ce premier chargement peut être lent. Le filtrage côté serveur garde les payloads petits, mais peut paraître lent si vous envoyez une requête à chaque frappe.

Concevez autour des saisies humaines. Débouncez les requêtes pendant la saisie. Pour de grands ensembles de résultats, utilisez un chargement progressif pour afficher quelque chose rapidement et rester fluide au fur et à mesure du défilement.

Facteur de décision 3 : permissions et exposition des données

Build a filtered list fast
Décrivez votre écran de liste, les filtres et les rôles, et laissez Koder.ai générer la première version fonctionnelle.

Les permissions doivent dicter votre approche plus que la vitesse. Si le navigateur reçoit des données qu'un utilisateur n'a pas le droit de voir, vous avez déjà un problème, même si vous les cachez derrière un bouton désactivé ou une colonne repliée.

Commencez par nommer ce qui est sensible sur cet écran. Certains champs sont évidents (emails, téléphones, adresses). D'autres sont faciles à oublier : notes internes, coûts ou marges, règles de tarification spéciales, scores de risque, indicateurs de modération.

Le piège majeur est « on filtre côté client, mais on n'affiche que les lignes permises ». Cela signifie quand même que l'ensemble complet a été téléchargé. N'importe qui peut inspecter la réponse réseau, ouvrir les devtools ou sauvegarder le payload. Cacher des colonnes dans l'UI n'est pas un contrôle d'accès.

Quand le filtrage côté serveur est le choix sûr par défaut

Le filtrage côté serveur est le choix sûr par défaut lorsque l'autorisation varie selon l'utilisateur, surtout quand différents utilisateurs peuvent voir différentes lignes ou champs.

Checklist rapide :

  • Des rôles différents voient-ils des lignes différentes (équipe seulement, région seulement, assigné à moi) ?
  • Des rôles différents voient-ils des champs différents (notes, tarification, PII) ?
  • Existe-t-il des règles au niveau ligne (propriétaire du compte, stade de l'affaire, flag « privé ») ?
  • L'export, le tri ou les totaux pourraient-ils révéler des informations restreintes ?
  • Une fuite du payload créerait-elle un problème de conformité ?

Si la réponse à une de ces questions est oui, appliquez le filtrage et la sélection de champs côté serveur. N'envoyez que ce que l'utilisateur est autorisé à voir, et appliquez les mêmes règles à la recherche, au tri, à la pagination et aux exports.

Exemple : dans une liste de contacts CRM, les commerciaux ne voient que leurs comptes tandis que les managers voient tout. Si le navigateur télécharge tous les contacts et filtre localement, un commercial peut récupérer les comptes cachés depuis la réponse. Le filtrage côté serveur évite cela en ne renvoyant jamais ces lignes.

Facteur de décision 4 : cache et fraîcheur

Le cache peut rendre un écran instantané. Il peut aussi afficher une vérité erronée. L'important est de décider ce que vous pouvez réutiliser, pendant combien de temps, et quels événements doivent l'invalider.

Commencez par choisir l'unité de cache. Cacher une liste complète est simple mais gaspille souvent de la bande passante et devient vite périmé. Cacher des pages fonctionne bien pour le scroll infini. Cacher des résultats de requête (filtre + tri + recherche) est précis, mais peut croître vite si les utilisateurs testent beaucoup de combinaisons.

La fraîcheur importe plus dans certains domaines. Si les données changent rapidement (niveaux de stock, soldes, statut de livraison), même un cache de 30 secondes peut perturber les utilisateurs. Si les données changent lentement (archives, données de référence), un cache plus long est généralement acceptable.

Planifiez l'invalidation avant de coder. Outre le temps, décidez ce qui doit forcer un rafraîchissement : créations/éditions/suppressions, changements de permissions, imports ou fusions en masse, transitions de statut, annulations/rollback et jobs en arrière-plan qui mettent à jour des champs filtrés.

Décidez aussi où le cache vit. La mémoire du navigateur accélère la navigation arrière/avant, mais peut fuiter des données entre comptes si vous ne la clé par utilisateur et organisation. Le cache backend est plus sûr pour les permissions et la cohérence, mais il doit inclure la signature complète du filtre et l'identité de l'appelant pour éviter les mélanges.

Étape par étape : comment choisir pour un nouvel écran

Le but est non négociable : l'écran doit paraître rapide sans fuir de données.

Un flux de décision pratique

  1. Commencez par la contrainte la plus forte. Si l'accès varie par rôle, équipe, région, organisation ou abonnement, les permissions l'emportent. Si le jeu de données est volumineux ou peut croître rapidement, la taille l'emporte.
  2. Par défaut, côté serveur lorsque les données sont volumineuses ou sensibles. Si vous ne seriez pas à l'aise de logguer l'ensemble des données dans la console du navigateur, ne les envoyez pas.
  3. N'utilisez le filtrage côté client que pour des listes petites, sûres et réutilisées. Dropdowns de statut, petites listes de tags, une seule page de résultats déjà validés.
  4. Définissez l'API avant l'UI. Notez les filtres, le tri, la pagination et les valeurs par défaut pour que le serveur et l'UI ne puissent pas diverger.
  5. Ajoutez des garde‑fous. Imposer une taille de page max, définir des timeouts, et décider du comportement de l'UI quand le filtrage est lent (afficher un spinner, garder les anciens résultats, proposer une réessai).

Erreurs courantes qui causent fuites ou lenteur

Lock the filter contract early
Utilisez le mode Planning pour définir filtres, tri, pagination et permissions avant de construire.

La plupart des équipes sont touchées par les mêmes motifs : une UI belle en démo, puis les vraies données, les vraies permissions et les vrais réseaux montrent les failles.

Erreurs qui fuient des données

L'échec le plus sérieux est de traiter le filtrage comme de la simple présentation. Si le navigateur reçoit des enregistrements qu'il ne devrait pas, vous avez déjà perdu.

Deux causes communes :

  • Envoyer l'ensemble complet au navigateur et filtrer localement « pour la vitesse ». N'importe qui peut inspecter la réponse ou interroger la mémoire.
  • Cacher des réponses filtrées sans attacher la clé de cache à l'identité de l'utilisateur, à l'organisation, au rôle ou à la version de la politique. Un changement de permission peut exposer silencieusement d'anciennes données.

Exemple : des stagiaires ne devraient voir que des leads de leur région. Si l'API renvoie toutes les régions et que le dropdown filtre dans React, les stagiaires peuvent toujours extraire la liste complète.

Erreurs qui rendent l'écran lent

La lenteur provient souvent d'hypothèses :

  • Penser que le filtrage côté client est toujours plus rapide. Avec 50 000 lignes, télécharger et parser peut être plus lent qu'une requête ciblée.
  • Oublier la pagination et les états de chargement. Un écran qui bloque en rendant une énorme liste paraît cassé même si la requête est correcte.

Un problème subtil mais pénible est des règles discordantes. Si le serveur traite « commence par » différemment de l'UI, les utilisateurs voient des totaux qui ne correspondent pas, ou des éléments qui disparaissent après rafraîchissement.

Checklist rapide avant le déploiement

Faites une passe finale avec deux états d'esprit : un utilisateur curieux et un jour de réseau pourri.

  • Sanité des payloads : confirmez que les réponses n'incluent jamais de lignes ou champs que l'utilisateur ne devrait pas voir, même si l'UI les cache. Méfiez‑vous des totaux, comptes de groupes ou IDs permettant d'inférer des données restreintes.
  • Logs sûrs : les filtres contiennent souvent des emails, noms ou IDs. N'enregistrez pas de valeurs sensibles dans des logs accessibles à beaucoup, ni le SQL complet ou le corps entier des requêtes.
  • Cohérence entre appareils : appliquez les mêmes filtres sur desktop et mobile. Les différences viennent souvent du tri côté client, des règles locales (casse, accents) ou des valeurs par défaut.
  • États clairs : loading, vide et erreur doivent être évidents. Testez les changements rapides (taper, supprimer, basculer) pour que l'UI ne scintille pas ou n'affiche pas des résultats périmés.
  • Garde‑fous en cas de pire scénario : taille de page max, plage de dates max et timeouts. Protégez contre les requêtes coûteuses (wildcards, trop de conditions OR, champs non indexés).

Un test simple : créez un enregistrement restreint et confirmez qu'il n'apparaît jamais dans le payload, les totaux ou le cache, même en filtrant largement ou en effaçant les filtres.

Scénario d'exemple : une liste de contacts CRM

Avoid slow queries in production
Ajoutez des limites de taille de page, des délais et des valeurs sûres pour que le filtrage reste réactif.

Imaginez un CRM avec 200 000 contacts. Les commerciaux ne voient que leurs comptes, les managers voient leur équipe et les admins voient tout. L'écran propose recherche, filtres (statut, propriétaire, dernière activité) et tri.

Le filtrage côté client échoue rapidement ici. Le payload est lourd, le premier chargement lent, et le risque de fuite élevé. Même si l'UI cache des lignes, le navigateur a quand même reçu les données. Vous surchargez aussi l'appareil : grands tableaux, tris lourds, exécutions répétées de filtres, forte consommation mémoire et crashs sur téléphones anciens.

Une approche plus sûre est le filtrage côté serveur avec pagination. Le client envoie ses choix de filtres et de recherche, et le serveur renvoie uniquement les lignes que l'utilisateur est autorisé à voir, déjà filtrées et triées.

Un schéma pratique :

  • Appliquez d'abord les permissions, puis les filtres et le tri.
  • Renvoyez une page à la fois (par exemple 50 lignes) plus un total.
  • Cachez prudemment (par utilisateur ou par rôle) pour ne pas mélanger des résultats selon les permissions.

Une petite exception où le filtrage côté client convient : des données minuscules et statiques. Un dropdown « Statut du contact » avec 8 valeurs peut être chargé une fois et filtré localement sans risque ni coût notable.

Prochaines étapes : documenter les décisions et réduire les réécritures

Les équipes ne se font pas souvent piéger en choisissant « mal » une fois. Elles se font piéger en prenant une décision différente pour chaque écran, puis en corrigeant des fuites et des pages lentes sous pression.

Rédigez une courte note de décision par écran avec les filtres : taille du jeu de données, coût d'envoi, ce que signifie « assez rapide », quels champs sont sensibles et comment les résultats doivent être mis en cache (ou non). Gardez serveur et UI alignés pour éviter d'avoir « deux vérités » du filtrage.

Si vous construisez rapidement des écrans dans Koder.ai (koder.ai), décidez en amont quels filtres doivent être appliqués côté backend (permissions et accès au niveau des lignes) et quels petits bascules UI peuvent rester dans la couche React. Ce choix évite souvent les réécritures les plus coûteuses plus tard.

FAQ

Quand devrais-je utiliser le filtrage côté serveur plutôt que côté client ?

Par défaut, choisissez le filtrage côté serveur lorsque les utilisateurs ont des permissions différentes, que le jeu de données est volumineux ou que vous tenez à des totaux et une pagination cohérents. N'utilisez le filtrage côté client que si l'ensemble complet est petit, sûr à exposer et rapide à télécharger.

Pourquoi le filtrage côté client pose-t-il un risque de sécurité même si je cache des lignes dans l'UI ?

Tout ce que le navigateur reçoit peut être inspecté. Même si l'interface cache des lignes ou des colonnes, un utilisateur peut toujours voir les données dans les réponses réseau, les caches ou les objets en mémoire.

Qu'est-ce qui fait que le filtrage paraît lent pour les utilisateurs ?

Cela arrive généralement quand vous envoyez trop de données puis filtrez/triez de grands tableaux à chaque frappe, ou quand vous envoyez une requête au serveur pour chaque pression de touche sans appliquer de debounce. Gardez les payloads petits et évitez les lourds traitements à chaque changement d'entrée.

Comment éviter des résultats incohérents quand on mélange filtrage client et serveur ?

Ayez une unique source de vérité pour les filtres « réels » : permissions, recherche, tri et pagination doivent être appliqués ensemble côté serveur. Limitez la logique côté client à de petits basculements UI qui ne changent pas l'ensemble de données sous-jacent.

Quelle est la façon la plus sûre de mettre en cache des listes filtrées ?

Le cache côté client peut afficher des données périmées ou fuir des données entre comptes s'il n'est pas correctement indexé. Le cache côté serveur est plus sûr pour les permissions, mais il doit inclure la signature complète de la requête (filtres) et l'identité de l'appelant pour éviter les mélanges.

Comment estimer si un jeu de données est « assez petit » pour un filtrage côté client ?

Posez deux questions : combien de lignes un utilisateur pourrait raisonnablement avoir, et quelle est la taille moyenne d'une ligne en octets. Si vous ne seriez pas à l'aise de le charger sur une connexion mobile typique ou sur un appareil ancien, déplacez le filtrage côté serveur et paginez.

Et si différents rôles peuvent voir différentes lignes ou champs ?

Côté serveur. Si les rôles, équipes, régions ou règles d'appartenance modifient ce qu'une personne peut voir, le serveur doit imposer l'accès au niveau des lignes et des champs. Le client ne doit recevoir que ce que l'utilisateur est autorisé à voir.

Comment concevoir l'API pour un filtrage côté serveur ?

Définissez d'abord le contrat des filtres et du tri : champs acceptés, tri par défaut, règles de pagination et comportement de la recherche (sensible à la casse, accents, correspondances partielles). Implémentez la même logique de façon cohérente côté backend et testez que totaux et pages correspondent.

Comment rendre le filtrage côté serveur rapide pour l'utilisateur ?

Appliquez un debounce lors de la saisie pour ne pas déclencher une requête à chaque touche, et conservez les anciens résultats visibles jusqu'à l'arrivée des nouveaux pour réduire les scintillements. Utilisez la pagination ou le chargement progressif pour afficher quelque chose rapidement sans bloquer en attendant une réponse massive.

Quelle est la bonne approche pour une liste CRM avec beaucoup d'enregistrements et des permissions strictes ?

Appliquez d'abord les permissions, puis les filtres et le tri, et ne renvoyez qu'une page plus un total. N'envoyez pas des « champs supplémentaires au cas où », et assurez-vous que les clés de cache incluent user/org/role pour qu'un commercial ne reçoive jamais des données destinées à un manager.

Related posts