ENbext.dev
DocumentationArchitecture

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Cycle de vie des demandes

Chaque requête HTTP adressée à un serveur bext passe par un pipeline bien défini. Comprendre ce pipeline vous aide à configurer la mise en cache, à écrire des plugins et à déboguer les problèmes de performances.

Aperçu#

code
Client
  |
  v
[1] TLS Termination (rustls / ACME)         ~0.5 ms (handshake) / ~0 ms (resumed)
  |
  v
[2] HTTP Parsing (actix-web / h3)            ~0.01 ms
  |
  v
[3] WAF Check                                ~0.05 ms
  |
  v
[4] Middleware Stack (on_request)             ~0.1-0.5 ms
  |  CORS -> Rate Limit -> Auth -> Tenant -> Tracing -> Plugin Middleware
  |
  v
[5] Route Matching                           ~0.01 ms
  |
  v
[6] Cache Lookup (L1 DashMap, L2 Redis)      ~0.01 ms (L1 hit) / ~1 ms (L2 hit)
  |
  v  (cache miss)
[7] Render / Static / Proxy                  ~5-50 ms (SSR) / ~0.01 ms (static)
  |
  v
[8] HTML Transforms                          ~0.1-1 ms
  |
  v
[9] Compression (brotli / gzip / zstd)       ~0.5-5 ms (miss) / ~0 ms (cached)
  |
  v
[10] Middleware Stack (on_response)           ~0.05 ms
  |
  v
[11] Response Delivery                       network-bound
  |
  v
[12] Post-Response Hooks (async)             non-blocking

Détails de l'étape#

1. Résiliation TLS#

Si TLS est activé (fonctionnalité tls), bext termine TLS en utilisant rustls avec ring crypto. Le SniCertResolver sélectionne le certificat correct en fonction du nom d'hôte SNI, prenant en charge les configurations multidomaines. L'agrafage OCSP est effectué en arrière-plan par OcspStapler.

Pour HTTP/3 (QUIC), l'écouteur quinn gère la négociation TLS 1.3 dans le cadre de la configuration de la connexion QUIC. HTTP/1.1 et HTTP/2 partagent les mêmes rustls ServerConfig.

Les premières connexions paient le coût total de la négociation (~ 0,5 ms). Les sessions reprises (tickets de session TLS) ignorent complètement la poignée de main.

2. Analyse HTTP#

actix-web analyse la requête HTTP (méthode, chemin, en-têtes, corps). Pour HTTP/3, la caisse h3 décode les en-têtes QPACK et fournit la même structure de requête. La requête analysée est enveloppée dans le type HttpRequest d'actix-web.

3. Vérification WAF#

Lorsque la fonctionnalité waf est activée, bext-waf inspecte la demande pour :

  • Filtrage IP -- Listes d'autorisation/refus CIDR.
  • Géoblocage - blocages au niveau national basés sur la géolocalisation IP.
  • Demande d'inspection -- détection basée sur les expressions régulières de l'injection SQL, du XSS, de la traversée de chemin et des empreintes digitales du scanner. Tous les modèles sont compilés une seule fois via OnceLock.
  • Détection de robots - analyse utilisateur-agent avec modes configurables (autoriser, défier, bloquer).
  • Atténuation DDoS – seuils de taux de connexion et de taux de requêtes.

Le WAF renvoie l'une des quatre décisions suivantes : Allow, Block (avec code d'état et motif), RateLimit (avec Réessayer après) ou Challenge (page de défi HTML JS). Les requêtes bloquées n’atteignent jamais la pile middleware.

4. Pile middleware (on_request)#

La pile middleware s’exécute par ordre de priorité. Le middleware intégré se déclenche en premier :

Priorité Intergiciel Action
100 CORS Définit les en-têtes de contrôle d'accès, gère le contrôle en amont des OPTIONS
200 Limiteur de débit Bucket de jetons par IP, renvoie 429 en cas de dépassement
300 Authentification Validation JWT ou recherche de session
400 Locataire Résout le locataire à partir du nom d'hôte ou de l'en-tête
500 Tracé Attribue un ID de demande, démarre la durée
600+ Intergiciel de plugin Logique de plugin personnalisée

Chaque middleware reçoit un RequestContext avec la méthode, le chemin, le nom d'hôte, les en-têtes, la chaîne de requête, l'adresse IP homologue et une carte extensions mutable pour transmettre les données aux gestionnaires en aval et à la phase on_response.

Un middleware peut court-circuiter le pipeline en renvoyant RequestAction::Respond(PluginResponse) avec un statut, des en-têtes et un corps personnalisés.

5. Correspondance d'itinéraire#

bext-core::route::process fait correspondre le chemin de la requête à la table de routage de l'application. Les routes sont compilées au moment de la construction à partir de la convention du système de fichiers ( src/pages/, src/app/ ) ou d'une configuration explicite. Les segments dynamiques ( [id] ), les itinéraires fourre-tout ( [...slug] ) et les groupes d'itinéraires sont pris en charge.

6. Recherche de cache#

Le cache ISR est un système à deux niveaux :

  • L1 (DashMap) -- carte de hachage simultanée en cours. Recherches inférieures à la microseconde. Limité à 10 000 entrées par défaut ( cache.isr.max_entries ) avec expulsion LRU.
  • L2 ( Redis ) -- en option, activé avec la fonctionnalité redis. ~1 ms aller-retour. Partagé sur plusieurs instances bext pour une mise à l'échelle horizontale.

Un accès au cache au niveau L1 saute entièrement les étapes 7 à 8. Un accès au cache en L2 favorise l'entrée en L1. Un système de protection contre les bousculades garantit qu'une seule requête est reconstruite en cas d'échec du cache : toutes les autres requêtes simultanées attendent le résultat.

7. Rendu / Statique / Proxy#

En cas d'échec du cache, la requête est envoyée en fonction du framework déclaré dans bext.config.toml :

  • PRISM pages ( [framework] type = "prism" ) -- expédiées via ssr_pipeline::prism, qui compile l'itinéraire correspondant à la première demande via bext - turbopack (avec le Passe de compilation PRISM repliant les sous-arbres JSX statiques en chaînes HTML avant le regroupement), puis évalue le JS résultant dans le Pool de rendu V8. Les requêtes ultérieures atteignent un isolat V8 chaud avec un contexte de page mis en cache. Sur le catalogue actuel de 38,3 Ko validé par octets, le rendu seul atteint en moyenne de 15,7 µs via la passe de compilation et de 75,3 µs via le runtime automatique JSX ; la latence complète des requêtes inclut en outre le travail de répartition environnant et le travail HTTP. La passe de compilation est désactivable via BEXT_PRISM_COMPILE=0. Voir PRISM et Pipeline de rendu PRISM de bout en bout.
  • Next.js / Pages RSC ( [framework] type = "nextjs" ) -- distribué à un pipeline d'évaluation V8 monothread qui possède un isolat de longue durée, met en cache un contexte de page chaud par route et pilote le renderToReadableStream de React 19 via un pilote de boucle d'événements personnalisé pour les composants de serveur asynchrone, Suspense et le Crochet use(promise). Lorsque [render] rsc = true, bext compile un bundle RSC par itinéraire avec la condition react-server et expose la charge utile Flight à /__bext/rsc/<path>. Le rendu typique est de 1 à 5 ms à chaud et de 30 à 50 ms à froid (compilation groupée + évaluation V8).
  • Hono / Express / applications de gestion d'extraction - compilées dans le pool V8 et appelé via le standard fetch(Request) ABI.
  • Sites construits avec un adaptateur ( Astro, SolidStart, SvelteKit, Qwik ) -- servi à partir de la sortie construite du framework, avec bext SSR pour les routes qui en ont besoin et une livraison statique pour le reste.
  • Fichiers statiques -- servis directement à partir du répertoire de sortie de build via des fichiers actix. Aucune surcharge de rendu.
  • Routes proxy - transmises à un serveur en amont (Bun, Node, PHP) via demande. Utilisé en mode hybride où bext gère SSR et le serveur framework gère les routes API.
  • Routes PHP -- lorsque la fonctionnalité php est activée, envoyées à le PhpPool pour l’exécution PHP en cours. Le mode Worker maintient le noyau du framework préchargé pendant environ 34 µs par requête.

8. Transformations HTML#

Après le rendu, bext applique les transformations HTML à temps de réponse :

  • Remplacement de l'îlot de serveur : les éléments <bext-island> sont remplacés par le contenu rendu.
  • Extraction des indices de préchargement : les balises <link> et <script> dans <head> sont extraites pour les premiers indices HTTP 103.
  • Injection de cadre Turbo - ajoute les attributs data-bext-turbo-root pour la navigation HTML sur fil.

Il s’agit de transformations en un seul passage basées sur des chaînes avec une surcharge minimale.

9. Compression#

Les corps de réponse sont compressés au premier échec et mis en cache dans le cache de compression (limité à 2 000 entrées avec expulsion basée sur l'horodatage). Les variantes gzip et brotli sont précalculées et stockées sous Arc<Vec<u8>>. Les requêtes ultérieures pour le même contenu servent la version pré-compressée sans aucun coût CPU.

L'en-tête Accept-Encoding détermine quelle variante est envoyée. Brotli est préféré lorsqu’il est disponible.

10. Pile middleware (on_response)#

La pile middleware s’exécute dans l’ordre de priorité inverse. Le on_response de chaque middleware reçoit le RequestContext et une structure ResponseHeaders mutable dans laquelle il peut modifier les codes d'état et injecter des en-têtes.

11. Livraison de la réponse#

La réponse finale est écrite sur la connexion client. Pour le streaming SSR, les morceaux sont produits par le renderToReadableStream du React 19 fonctionnant à l'intérieur du V8 et pompés jusqu'au bout par le pilote de boucle d'événement personnalisé du bext ( collect_async_render_result ) avant d'être envoyés au fil.

12. Crochets post-réponse#

Une fois la réponse entièrement envoyée, les plug-ins de cycle de vie reçoivent un événement on_request_complete avec le chemin, la méthode, l'état, l'état du cache, l'heure de rendu, l'ID de locataire et d'autres métadonnées. Ces hooks se déclenchent de manière asynchrone et ne doivent pas bloquer la connexion.

Remarque

Les étapes 7 à 8 sont entièrement ignorées en cas d'accès au cache L1. Pour les pages PRISM, cela signifie que la latence SSR tombe à moins d'une milliseconde — la réponse est fournie par le DashMap en cours avant que tout travail V8 ne soit effectué.

Conseil

Si votre middleware doit transmettre des données de la phase de demande à la phase de réponse, écrivez-les dans la carte extensions sur RequestContext — cette carte est transmise à toutes les étapes.

En rapport#

Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.