Maison > interface Web > js tutoriel > le corps du texte

Les actions du serveur ont été corrigées

Linda Hamilton
Libérer: 2024-10-21 06:22:02
original
737 Les gens l'ont consulté

Les actions serveur sont apparues comme une idée visant à réduire le code client et à simplifier les interactions qui nécessitent une communication avec le serveur. C'est une excellente solution qui permet aux développeurs d'écrire moins de code. Cependant, sa mise en œuvre dans d'autres cadres présente plusieurs défis à ne pas négliger.

Dans cet article, nous parlerons de ces problèmes et de la manière dont Brisa nous avons trouvé une solution.

Pourquoi avez-vous besoin d’actions serveur ?

Pour comprendre ce que fournissent les actions du serveur, il est utile de revoir comment se déroulait la communication avec le serveur. Vous avez probablement l'habitude d'effectuer les actions suivantes pour chaque interaction avec le serveur :

  1. Capturer un événement de navigateur (Client)
  2. Normaliser et sérialiser les données (Client)
  3. Faire une requête au serveur (Client)
  4. Traiter la requête dans une API de point de terminaison (Serveur)
  5. Répondez avec les données nécessaires (Serveur)
  6. Attendez la réponse du serveur et traitez-la (Client)
  7. Mettre à jour les données sur le client et rendre les modifications (Client)

Ces sept actions sont répétées à chaque interaction. Par exemple, si vous avez une page avec 10 interactions différentes, vous répéterez 10 fois un code très similaire, en modifiant uniquement les détails tels que le type de demande, l'URL, les données envoyées et le statut du client.

Un exemple familier serait
une :

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Et dans le serveur :

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Augmentation de la taille du bundle client... et frustration des développeurs.

Server Actions have been fixed


Développeur frustré

Comment fonctionnent les actions du serveur

Les

Actions du serveur encapsulent ces actions dans un Appel de procédure à distance (RPC), qui gère la communication client-serveur, réduisant le code sur le client et centralisant la logique sur le serveur :

  1. Capturer un événement de navigateur (Client RPC)
  2. Normaliser et sérialiser les données (RPC Client)
  3. Faire une requête au serveur RPC (RPC Client)
  4. Exécuter l'action sur le serveur avec les données (RPC Server)
  5. Option 1 :
  • Rendu depuis le serveur et envoyer le streaming au client (RPC Server)
  • Traitez les morceaux du flux pour que les modifications soient visibles (RPC Client)
  1. Option 2 :
  • Répondez avec les données nécessaires et transférez les propriétés du magasin du serveur vers le magasin client (Serveur RPC)
  • Faire réagir les signaux qui écoutaient les changements aux changements dans le magasin (RPC Client)

Ici, tout est fait pour vous par le Brisa RPC.

Server Actions have been fixed


Appel de procédure à distance

Ceci serait le code d'un composant serveur :

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ici, les développeurs n'écrivent pas de code client, puisqu'il s'agit d'un composant serveur. L'événement onInput est reçu après le rebond, géré par le RPC client, tandis que le RPC serveur utilise des « signaux d'action » pour déclencher les composants Web dont les signaux sont enregistrés avec cette propriété de magasin.

Comme vous pouvez le constater, cela réduit considérablement le code du serveur et, mieux encore, la taille du code sur le client n'augmente pas à chaque interaction. Le code client RPC occupe 2 Ko fixes, que vous ayez 10 ou 1 000 interactions de ce type. Cela signifie que augmenter de 0 octet la taille du bundle client, en d'autres termes, n'augmente pas.

Server Actions have been fixed


0 octet sur la taille du bundle client

De plus, en cas de besoin d'un rendu, celui-ci est effectué sur le serveur et est renvoyé en streaming HTML, ce qui permet à l'utilisateur de voir les modifications beaucoup plus tôt que de la manière traditionnelle où il fallait faire ce travail sur le client après la réponse du serveur.

De cette façon :

  • Améliorer l'expérience utilisateur (UX)
  • Améliorer l'expérience de développement (DX)

Server Actions have been fixed


Développeur heureux

Différences entre Brisa Server Actions et d'autres frameworks

1. Nombre d'événements à capturer

Dans d'autres frameworks tels que React, ils se sont concentrés sur les actions uniquement faisant partie du formulaire onSubmit, au lieu de n'importe quel événement.

C'est un problème, car il existe de nombreux événements hors formulaire qui doivent également être gérés à partir d'un composant serveur sans ajouter de code client. Par exemple, un onInput d'une entrée pour faire des suggestions automatiques, un onScroll pour charger un défilement infini, un onMouseOver pour faire un survol, etc.

Server Actions have been fixed


Les applications sont plus interactives que prévu

2. Avoir plus de contrôles HTML sur les actions du serveur

De nombreux frameworks ont également vu la bibliothèque HTMX comme une alternative très différente aux actions serveur, alors qu'en fait elle a apporté de très bonnes idées qui peuvent être combinées avec les actions serveur pour avoir plus de potentiel en ajoutant simplement des attributs supplémentaires dans le HTML que le Le client RPC peut en prendre en compte, comme le debounceInput que nous avons vu auparavant. Également d'autres idées HTMX comme l'indicateur pour afficher un spinner lors de la demande, ou être capable de gérer une erreur dans le client RPC.

Server Actions have been fixed


Idées HTML

3. Séparation des préoccupations

Lorsque les actions serveur ont été introduites dans React, il y a eu un nouveau changement de paradigme que de nombreux développeurs ont dû changer de puce mentale lorsqu'ils travaillaient avec elles.

Nous voulions le rendre aussi familier autant que possible à la plateforme Web, de cette façon, vous pouvez capturer l'événement sérialisé à partir du serveur et utiliser ses propriétés. Le seul événement un peu différent est le onSubmit qui a déjà transféré le FormData et possède la propriété e.formData, néanmoins, le reste des propriétés de l'événement sont interactives. Ceci est un exemple de réinitialisation d'un formulaire :

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet exemple, il n'y a aucun code client et lors de l'action du serveur vous pouvez désactiver le bouton de soumission avec l'indicateur, en utilisant CSS, afin que le formulaire ne puisse pas être soumis deux fois, et au en même temps après avoir effectué l'action sur le serveur et accéder aux données du formulaire avec e.formData puis réinitialiser le formulaire en utilisant la même API de l'événement.

Mentalement, c'est très similaire au travail avec la Plateforme Web. La seule différence est que tous les événements de tous les composants du serveur sont des actions du serveur.

De cette façon, il y a une vraie séparation des préoccupations, où il n'est PAS nécessaire de mettre "user server" ou "use client" dans votre composants plus.

Gardez simplement à l'esprit que tout fonctionne uniquement sur le serveur. La seule exception concerne le dossier src/web-components qui s'exécute sur le client et là les événements sont normaux.

Server Actions have been fixed


Deux mondes différents, mais en accord

4. Propagation des événements

Dans Brisa, les actions du serveur sont propagées entre les composants du serveur comme s'il s'agissait d'événements DOM. C'est-à-dire qu'à partir d'une action serveur, vous pouvez appeler un événement d'un accessoire d'un composant serveur, puis l'action serveur du composant serveur parent est exécutée, etc.

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans ce cas, l'événement onAfterMyAction est exécuté sur le composant parent et une action peut être effectuée sur le serveur. Ceci est très utile pour effectuer des actions sur le serveur qui affectent plusieurs composants du serveur.

Server Actions have been fixed


Propagation de l'action

4. Communication entre les deux mondes

Surtout ces dernières semaines, les composants Web ont été un peu mal vus après plusieurs discussions sur X (anciennement Twitter). Cependant, faisant partie du HTML, c'est le meilleur moyen d'interagir avec les actions du serveur pour plusieurs raisons :

  1. Vous pouvez capturer n'importe quel événement de composant Web à partir du serveur et générer une communication client-serveur. Exemple . Ceci est très puissant, car tous les événements à l'intérieur du composant Web ne sont que la logique du client sans y mettre de logique de serveur, simplement à partir du serveur lors de la consommation du composant Web, vous pouvez effectuer des actions de serveur.
  2. Le protocole HTTP peut être utilisé pour ce pour quoi il a été conçu, pour transférer de l'Hypertexte (HTML) en streaming, de cette façon si après une re- le rendu à partir d'une action serveur, tout attribut d'un composant Web est mis à jour, l'algorithme de différence du client RPC permet de mettre à jour le composant Web sans trop d'effort. Les attributs des composants Web dans Brisa sont des signaux qui font réagir les parties internes du composant Web sans avoir à effectuer un nouveau rendu. Ce processus dans d'autres frameworks devient très compliqué, obligeant le serveur RPC à traiter JSON ou JS via le réseau, au lieu de HTML, ce qui rend la mise en œuvre du streaming plus compliquée.

L'utilisation d'attributs dans les composants Web nécessite une sérialisation de la même manière que la transmission de données du serveur au client sans utiliser de composants Web. Par conséquent, en utilisant les deux, il n'y a aucune sérialisation supplémentaire à gérer.

Remarque : Le streaming HTML et son traitement avec l'algorithme de comparaison sont quelque chose que j'ai expliqué dans cet autre article si vous êtes intéressé.

Server Actions have been fixed


Hypertexte en streaming sur le fil

5. Nouveau concept : signaux d'action

Dans Brisa, nous avons ajouté un nouveau concept pour donner encore plus de puissance aux Actions du Serveur, ce concept s'appelle "Signaux d'Action". L'idée des « Signaux d'action » est que vous avez 2 magasins, un sur le serveur et un sur le client.

Pourquoi 2 magasins ?

Le magasin de serveur vit uniquement au niveau de la demande. Et vous pouvez partager des données qui ne seront pas visibles par le client. Par exemple, vous pouvez demander au middleware de définir l'utilisateur et d'avoir accès aux données utilisateur sensibles dans n'importe quel composant serveur. En vivant au niveau des requêtes, il est impossible d'avoir des conflits entre différentes requêtes, puisque chaque requête a son propre magasin et n'est PAS stockée dans aucune base de données, lorsque le la requête est terminée, elle meurt par défaut.

En revanche, dans le magasin client, c'est un magasin qui chaque propriété lorsqu'elle est consommée est un signal, c'est-à-dire, si il est mis à jour, le composant Web qui écoutait ce signal réagit.

Cependant, le nouveau concept de "Action Signal" est que nous pouvons prolonger la durée de vie du magasin du serveur au-delà de la demande. Pour ce faire il faut utiliser ce code :

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cette méthode transferToClient, partage les données du serveur avec le magasin client et converties en signaux. De cette façon, il ne sera souvent pas nécessaire d'effectuer un nouveau rendu depuis le serveur, vous pouvez simplement, à partir d'une action du serveur, faire réagir les signaux des composants Web qui écoutaient ce signal.

Ce transfert de magasin rend la vie du serveur magasin désormais :

Rendu du composant serveur initial → Client → Action du serveur → Client → Action du serveur...

On passe donc de vivre uniquement au niveau de la demande à vivre en permanence, compatible avec la navigation entre les pages.

Server Actions have been fixed


Partager des données entre les deux mondes (serveur/client)

Exemple :

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet exemple, nous prolongeons la durée de vie de la propriété du magasin d'erreurs, non pas pour être utilisée sur le client, mais pour être réutilisée dans l'Action Serveur puis enfin dans le rerendu de l'Action Serveur. Dans ce cas, s’agissant d’une donnée non sensible, il n’est pas nécessaire de la chiffrer. Cet exemple de code se produit sur le serveur, même le rendu et l'utilisateur verra les erreurs après ce rendu sur le serveur où le RPC du serveur enverra les morceaux HTML en streaming et le RPC client le traitera pour faire la différence et afficher le erreurs pour donner des commentaires à l'utilisateur.

6. Chiffrez uniquement les données sensibles

Si dans une action du serveur, une variable qui existait au niveau du rendu est utilisée, au niveau de la sécurité, de nombreux frameworks comme Next.js 14 ce qu'ils font est de crypter ces données pour créer un instantané des données utilisées au niveau du rendu. le moment du rendu. C'est plus ou moins bien, mais le crypter les données toujours a un coût de calcul associé et il ne s'agit pas toujours de données sensibles.

Dans Brisa, pour résoudre ce problème, il existe différentes requêtes, où dans le rendu initial elle a une valeur, et dans l'action du serveur, vous pouvez capturer la valeur qu'elle a dans cette requête.

<input
  debounceInput={300}
  onInput={async (e) => {
    // All this code only runs on the server
    const data = await search(e.target.value);
    store.set("query", data);
    store.transferToClient(["query"]);
  }}
/>
Copier après la connexion
Copier après la connexion

Ceci est utile dans certains cas mais pas toujours, par exemple si vous faites un Math.random, ce sera certainement différent entre le rendu initial et l'exécution de l'action serveur.

<input
  onInput={(e) => {
    // debounce
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(() => {
      fetch("/api/search", {
        method: "POST",
        body: JSON.stringify({ query: e.target.value }),
      })
        .then((res) => res.json())
        .then((data) => {
          setState({ data });
        });
    }, 300);
  }}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est pourquoi nous avons créé le concept de "Signaux d'action", pour transférer des données du magasin serveur vers le magasin client, et le développeur peut décider de crypter le ou non à volonté.

Parfois, au lieu d'interroger la base de données à partir de l'action serveur, vous souhaiterez peut-être transférer des données qui existent déjà dans le rendu initial même si cela nécessite un cryptage associé. Pour ce faire, vous utilisez simplement :

app.post("/api/search", async (req, res) => {
  const { query } = req.body;
  const data = await search(query);
  res.json(data);
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Quand vous le faites :

<input
  debounceInput={300}
  onInput={async (e) => {
    // All this code only runs on the server
    const data = await search(e.target.value);
    store.set("query", data);
    store.transferToClient(["query"]);
  }}
/>
Copier après la connexion
Copier après la connexion

À l'intérieur d'un composant Web (client) sera toujours crypté, mais sur le serveur, il sera toujours déchiffré.

Remarque : Brisa utilise aes-256-cbc pour le cryptage, une combinaison d'algorithmes cryptographiques utilisés pour crypter en toute sécurité les informations recommandées par OpenSSL. Les clés de chiffrement sont générées lors de la construction de votre projet.

Server Actions have been fixed


Partager des données cryptées entre les deux mondes (serveur/client)

Conclusion

Chez Brisa, bien que nous aimions prendre en charge l'écriture de composants Web facilement, l'objectif est de pouvoir créer un SPA sans code client et d'utiliser des composants Web uniquement lorsqu'il s'agit d'une interaction purement client ou que l'API Web doit être touchée. C'est pourquoi les actions serveur sont si importantes, car elles permettent des interactions avec le serveur sans avoir à écrire de code client.

Nous vous encourageons à essayer Brisa, il vous suffit d'exécuter cette commande dans le terminal : bun create brisa, ou d'essayer un exemple pour voir comment cela fonctionne.

Références

  • Convention sur les actions du serveur
  • Comportement des actions du serveur
  • Formulaires avec actions du serveur
  • Actions imbriquées
  • Validation côté serveur et gestion des erreurs
  • Annuler une action du serveur
  • Mises à jour optimistes
  • Re-rendu en action
  • Naviguez vers une autre page avec les actions du serveur
  • Accès aux Cookies
  • Sécurité dans les actions du serveur
  • Signaux d'action
  • Transférer des données sensibles
  • Props dans les actions du serveur
  • Utilisation des actions du serveur dans un proxy inverse

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal