Guide de développement du guide

Pratiques d'applications Web hautes performances

introduire

fibjs est un framework de serveur d'applications hautes performances conçu principalement pour le développement backend Web. Il est construit sur le moteur JavaScript Google v8 et choisit une solution de concurrence différente des rappels traditionnels. fibjs utilise des fibres pour isoler la complexité métier causée par les appels asynchrones au niveau de la couche framework, réduisant ainsi considérablement la difficulté de développement et réduisant les problèmes de performances causés par un traitement asynchrone fréquent dans l'espace utilisateur.

La conception de fibjs accorde une grande attention aux performances. Les modules réseau IO et HTTP intégrés adoptent un modèle d'E/S non bloquant basé sur les événements, afin que les développeurs puissent facilement implémenter des applications serveur de haute fiabilité. Et comme la couche inférieure est implémentée en C++, fibjs a des performances très supérieures et peut facilement gérer un accès simultané élevé et fournir des services extrêmement stables et fiables.

Dans le même temps, fibjs prend également en charge WebSocket, un protocole de communication full duplex basé sur le protocole TCP. Il établit une connexion ininterrompue entre le navigateur et le serveur, permet la transmission de données bidirectionnelle en temps réel et peut prendre en charge les données. dans n'importe quel format. WebSocket peut être utilisé pour mettre en œuvre facilement des applications de communication en temps réel avec de meilleurs effets de communication.

En bref, fibjs met non seulement l'accent sur les hautes performances et la haute fiabilité, mais fournit également des fonctionnalités de communication en temps réel telles que WebSocket. C'est un framework très adapté au développement d'applications Web à haut débit.

Configuration de l'environnement de développement

Avant de commencer le développement de fibjs, nous devons préparer l'environnement de développement. Ce chapitre expliquera comment installer fibjs, comment utiliser l'outil fibjs pour initialiser le projet et comment utiliser l'environnement de développement intégré IDE.

Installer fibjs

Pour différents systèmes d'exploitation, les méthodes d'installation de fibjs sont légèrement différentes.

Pour les utilisateurs Linux et macOS, fibjs peut être installé à l'aide de la commande suivante :

1
curl -s https://fibjs.org/download/installer.sh | sh

Si vous utilisez macOS et utilisez le gestionnaire de packages Homebrew, vous pouvez également l'installer à l'aide de la commande suivante :

1
brew install fibjs

Pour les utilisateurs Windows, vous devez télécharger le programme d'installation depuis le site officiel de fibjs, puis suivre les instructions pour l'installer.

Créez un nouveau projet en utilisant fibjs –init

Après avoir installé fibjs, vous pouvez utiliser l'outil fibjs pour créer rapidement de nouveaux projets. Utilisez la commande suivante pour créer un modèle de projet de base :

1
fibjs --init

Cette commande créera une nouvelle structure de projet dans le répertoire actuel, y compris package.json, qui est utilisé pour stocker les informations de base du projet et les informations sur les dépendances.

Rédaction d'applications Web

Le développement d'applications Web est actuellement le scénario d'application le plus couramment utilisé de fibjs. fibjs fournit une série d'outils et de modules pour nous aider à créer des applications Web plus rapidement.

Écrire un serveur HTTP

  • Importez d’abord le module http ;
  • Instanciez http.Server et écoutez les demandes.
  • Le serveur est démarré via la fonction start.
1 2 3 4 5 6
const http = require('http'); const server = new http.Server(8080, (req) => { req.response.write('Hello World!'); }); server.start();

Analyser les paramètres d'URL et le corps de la requête

L'analyse des paramètres d'URL et des corps de requête est très importante et est utilisée dans diverses applications côté serveur. Dans fibjs, les paramètres d'URL entrants peuvent être analysés directement via req.query, et le corps de la requête est lu via req.body.

1 2 3 4 5 6 7 8
const http = require('http'); const server = new http.Server(8080, (req) => { var name = req.query.get('name'); var msg = name ? `Hello ${name}!` : 'Hello world!'; req.response.write(msg); }); server.start();

Implémenter le contrôle d’accès à l’interface

Restreindre l’accès des utilisateurs via les interfaces est un scénario très courant. Vous trouverez ci-dessous un exemple simple.

1 2 3 4 5 6 7 8 9 10
const http = require('http'); const server = new http.Server(8080, (req) => { if (req.headers.get('auth') === 'ok') { req.response.write('Hello World!'); } else { req.response.write('Access Denied!'); } }); server.start();

Ajouter un traitement de routage

Le routage est l'un des concepts les plus importants dans une application Web. Le routage fait référence à la distribution des requêtes reçues aux processeurs selon certaines règles. Dans fibjs, vous pouvez écrire votre propre module de routage et le lier au serveur http, puis effectuer la correspondance d'URL et le traitement correspondant via une analyse d'itinéraire personnalisée.

1 2 3 4 5 6 7 8 9
const http = require('http'); const { Router } = require('mq'); var router = new Router(); router.get('/hello/:name', function (req, name) { req.response.write('hello, ' + name); }); var svr = new http.Server(8080, router); svr.start();

L'exemple ci-dessus peut également être implémenté avec une syntaxe plus simple :

1 2 3 4 5 6 7 8
const http = require('http'); var svr = new http.Server(8080, { '/hello/:name': function (req, name) { req.response.write('hello, ' + name); } }); svr.start();

Gestion des erreurs et journalisation

Dans fibjs, vous pouvez capturer des exceptions logiques via des blocs try-catch et les afficher dans des fichiers journaux pour le débogage et l'enregistrement ; s'il s'agit d'exceptions fatales, elles peuvent être envoyées directement au framework supérieur pour traitement.

1 2 3 4 5 6 7 8 9 10
const console = require('console'); const http = require('http'); const server = new http.Server(8080, (req) => { try { // ... } catch (e) { console.log(e.message, e.stack); } });

demande inter-domaines

Dans fibjs, nous pouvons utiliser la méthode activateCrossOrigin pour autoriser les requêtes inter-domaines. Voici un exemple de code expliquant comment créer un serveur http et autoriser les requêtes inter-domaines :

1 2 3 4 5 6 7 8
const http = require('http'); const server = new http.Server(8080, (req) => { req.response.write('Hello World!'); }); server.enableCrossOrigin(); // enable cross domain request server.start();

Dans l'exemple ci-dessus, nous avons créé un serveur http avec le port 8080. La méthode activateCrossOrigin() autorise les requêtes d’origine croisée.

Lorsque vous utilisez activateCrossOrigin pour autoriser les requêtes inter-domaines, vous pouvez spécifier les en-têtes inter-domaines autorisés à être reçus en passant un paramètre allowHeaders. Par défaut, la valeur AllowHeaders est Content-Type.

L'exemple de code est le suivant :

1 2
// enable "Content-Type" and "Authorization" headers in cross domain request server.enableCrossOrigin("Content-Type, Authorization");

Dans le code ci-dessus, la valeur de allowHeaders est « Content-Type, Authorization », ce qui signifie que le serveur est autorisé à recevoir les deux en-têtes inter-domaines « Content-Type » et « Authorization ». Si la requête contient d'autres en-têtes, elle sera rejetée par le serveur.

Il convient de noter que lorsque nous utilisons activateCrossOrigin pour configurer la possibilité de recevoir des en-têtes inter-domaines, nous devons également définir l'en-tête de requête correspondant lors de l'envoi de requêtes inter-domaines, sinon il sera également rejeté par le serveur.

WebSockets

Le protocole WebSocket est un protocole de communication full duplex basé sur le protocole TCP. Il établit une connexion ininterrompue entre le navigateur et le serveur, peut réaliser une transmission de données bidirectionnelle en temps réel et prendre en charge la transmission de données dans n'importe quel format. Dans fibjs, le module de support WebSocket fournit les interfaces API correspondantes, qui peuvent réaliser le développement du serveur et du client WebSocket.

Utilisez le module WebSocket natif de fibjs pour implémenter WebSocket côté serveur

Côté serveur, les requêtes HTTP peuvent être converties en connexions WebSocket via la fonction de mise à niveau. Lors de la création d'un objet serveur http, vous pouvez utiliser ws.upgrade(callback) et le transmettre à la méthode http.start() pour convertir la requête http en WebSocket.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
var ws = require('ws'); var http = require('http'); var server = new http.Server(8080, { '/ws': ws.upgrade(function(conn, req) { console.log('a client connected.'); // listening for message events conn.onmessage = function(evt) { console.log('received message: ', evt.data); // echo the message back to client conn.send('Server: ' + evt.data); }; // listening for close events conn.onclose = function(code, reason) { console.log('closed.'); }; // listening for error events conn.onerror = function(err) { console.log(err); }; }) }); server.start();

Dans l'exemple ci-dessus, nous pouvons surveiller l'événement de message envoyé par le client et l'événement de fermeture de connexion entre le serveur et le client. Lorsque le serveur reçoit le message client, il renvoie le même message au client. À ce stade, une simple communication point à point WebSocket est implémentée.

Implémenter l’interaction avec le stockage de données

Lorsque vous utilisez WebSocket pour la communication, en plus de simplement envoyer et recevoir des messages, vous devez également prendre en compte des opérations telles que le stockage persistant et l'interrogation de données. À ce stade, vous devez utiliser la base de données. Vous pouvez utiliser le module db intégré à fibjs pour interagir avec la base de données.

L'exemple de code est le suivant :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
var ws = require("ws"); var http = require("http"); var db = require("db"); // open a mysql connection var mysql = db.openMySQL("mysql://root:password@localhost/dbname"); var server = new http.Server(8080, { "/ws": ws.upgrade(function(conn, req) { console.log("a client connected."); // listening for message events conn.onmessage = function(evt) { console.log("received message: ", evt.data); // use execute to query the data var rs = mysql.execute("SELECT * FROM user WHERE name=?", evt.data.toString()); conn.send(JSON.stringify(rs)); }; // listening for close events conn.onclose = function(code, reason) { console.log("closed."); }; // listening for error events conn.onerror = function(err) { console.log(err); }; }) }); server.start();

Dans l'exemple ci-dessus, nous avons d'abord utilisé la méthode openMySQL du module db pour créer un objet de connexion à la base de données MySQL mysql, puis après avoir écouté le message du client, nous avons utilisé la méthode d'exécution pour exécuter directement la requête SQL et obtenir les enregistrements qui remplir les conditions. Enfin, les résultats de la requête sont renvoyés au client via le protocole WebSocket.

Il convient de noter que dans le développement réel, la gestion des exceptions et la sécurité des données doivent être bien faites.

En résumé, grâce au module db, nous pouvons interagir facilement et facilement avec la base de données, combinée au protocole WebSocket, pour implémenter des applications Web hautes performances en temps réel.

Implémenter la communication client-serveur WebSocket

Côté client, vous pouvez vous connecter à un serveur WebSocket en créant une instance WebSocket et en spécifiant une URL, puis envoyer des messages au serveur.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
var ws = require('ws'); // create a WebSocket object and connect to ws://localhost:8080/ws var conn = new ws.Socket('ws://localhost:8080/ws'); // listening for open events conn.onopen = function() { conn.send('hello'); } // listening for message events conn.onmessage = function(evt) { console.log('received message:', evt.data); } // listening for close events conn.onclose = function(code, reason) { console.log('closed.'); } // listening for error events conn.onerror = function(err) { console.log(err); }

Dans le code client ci-dessus, nous créons une instance WebSocket et spécifions son URL. Une fois la connexion établie avec succès, nous pouvons envoyer des messages au serveur. Lorsque le serveur reçoit le message client, il renvoie le même message au client. À ce stade, une simple communication point à point WebSocket est implémentée.

Avantages et scénarios d'utilisation de WebSocket

Le protocole WebSocket a un modèle de communication bidirectionnel typique, permettant au serveur de transmettre activement des données au client. Il est souvent utilisé pour mettre en œuvre des discussions, des jeux en ligne et d'autres occasions qui nécessitent un temps réel et une grande immédiateté. Par rapport aux autres protocoles de transmission, le protocole WebSocket présente les avantages suivants :

• Hautes performances en temps réel, prend en charge la communication bidirectionnelle • Spécification de protocole simple, facile à utiliser • Capable de gérer un grand nombre de connexions simultanées • Prend en charge les connexions longues, réduisant le temps de transmission réseau

Les scénarios d'utilisation les plus courants de WebSocket incluent le chat Web, les batailles de jeu, la lecture en ligne et la messagerie instantanée.

En résumé, grâce au module de support WebSocket, il est très simple à mettre en œuvre et les développeurs peuvent rapidement créer leurs propres applications Web.

Test de l'unité

Cadres de test et méthodes de test

Dans le processus de développement logiciel, les tests sont un lien très important, et les tests unitaires en sont une partie importante.Les tests unitaires peuvent vérifier efficacement si le code répond à la conception et aux exigences et éviter les erreurs introduites lorsque le code est modifié. D'une manière générale, le principe des tests unitaires est de tester chaque fonction et méthode pour s'assurer que les entrées et sorties de chaque fonction et méthode sont correctes.

Un framework de test est une base de code utilisée pour écrire, exécuter et vérifier des cas de test. Il fournit des fonctions de gestion, d'exécution et de reporting des cas de test. En JavaScript et Node.js, les frameworks de tests unitaires populaires incluent Mocha, Jest et Jasmine. Dans fibjs, nous avons également notre propre framework de test, le module test.

Dans le processus de tests unitaires, les méthodes de test couramment utilisées incluent les tests en boîte noire et les tests en boîte blanche.

Le test boîte noire est une méthode de test qui prend uniquement en compte l'entrée et la sortie d'une fonction sans tenir compte des détails d'implémentation à l'intérieur de la fonction. Les tests en boîte noire sont basés sur l'analyse des exigences et les spécifications de conception. Grâce à l'analyse et à l'exécution des cas de test, ils déterminent si le programme présente des erreurs logiques, des erreurs de limites, des problèmes de sécurité, etc. Son avantage est que le processus de test est simple et les résultats du test sont fiables. Son inconvénient est que le test ne peut pas couvrir tous les chemins du programme.

Le test en boîte blanche est une méthode de test qui prend en compte les détails d'implémentation internes d'une fonction, notamment les instructions conditionnelles, les instructions de boucle, la récursivité et la couverture du code. Ces tests peuvent identifier d'éventuels problèmes dans l'interaction entre les données partagées et le code. L'avantage des tests en boîte blanche est qu'ils peuvent couvrir tous les chemins du programme. L'inconvénient est que le processus de test est plus compliqué et que les résultats des tests sont affectés par l'environnement et les méthodes de mise en œuvre.

Rédiger des cas de tests à l'aide du module de test

Dans fibjs, nous pouvons utiliser le module de test pour écrire des cas de test pour le serveur Web. Voici un exemple simple :

1 2 3 4 5 6 7 8 9 10 11 12 13 14
var test = require('test'); test.setup(); var http = require('http'); describe('Web server test', () => { it('should return hello world', () => { var r = http.get('http://localhost:8080/hello'); assert.equal(r.statusCode, 200); assert.equal(r.data.toString(), 'Hello World'); }); }); test.run();

Dans cet exemple, nous utilisons les fonctions décrire et it pour définir respectivement le module de test et le scénario de test, et utilisons la fonction assert pour la vérification des assertions.

Dans la fonction de description, nous pouvons définir plusieurs fonctions informatiques pour tester respectivement différents scénarios. Dans chaque fonction it, nous pouvons utiliser la fonction http.get pour simuler une requête HTTP GET, obtenir la réponse à la requête et effectuer une vérification d'assertion telle que assertTrue et assertEqual.

En rédigeant des cas de test, vous pouvez tester efficacement l'exactitude des fonctions et des modules, garantir la qualité du produit et également améliorer la maintenabilité du code.

Mise à jour chaude

La mise à jour à chaud fait référence à la mise à jour du code du serveur sans arrêter le service. Au cours du processus de développement du programme, afin d'itérer rapidement, des ajustements de code et de nouvelles fonctions sont souvent nécessaires. Grâce à la mise à jour à chaud, vous pouvez utiliser un nouveau code pour effectuer le travail d'itération plus efficacement sans arrêter le service.

Dans fibjs, nous pouvons utiliser le module SandBox pour réaliser des mises à jour à chaud fluides. Le module SandBox peut fournir un environnement d'exécution sécurisé et simuler des variables globales et d'autres fonctions. Pour une mise en œuvre spécifique, veuillez vous référer aux étapes suivantes :

  • Chargez les fichiers de code qui doivent être mis à jour (tels que web.js).
  • Via SandBox, créez un nouveau module de sécurité, chargez web.js dans le module et générez le module de sécurité. Remontez le gestionnaire du service en cours d'exécution via le module de sécurité généré.
  • Le serveur continue de traiter les requêtes précédentes et les nouvelles requêtes seront montées sur le nouveau gestionnaire.

Voici un exemple de code qui utilise le module SandBox pour implémenter des mises à jour à chaud fluides :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
const fs = require('fs'); const http = require('http'); const { SandBox } = require('vm'); let FILE_PATH = './web.js'; let handler = new SandBox().require(FILE_PATH).handler; const server = new http.Server(8080, handler); server.start(); fs.watch(FILE_PATH, (event, filename) => { handler = new SandBox().require(FILE_PATH).handler; server.handler = handler; console.log(`[${new Date().toLocaleString()}] server reloaded.`); });

Dans ce code, nous chargeons d'abord le code dans web.js au démarrage du programme, puis créons une instance SandBox et chargeons le code dans l'instance. Après cela, nous avons créé un nouveau serveur HTTP et utilisé les méthodes du gestionnaire pour traiter la demande.

Dans le code, nous utilisons fs.watch pour surveiller les modifications dans le fichier web.js. Une fois le fichier modifié, nous rechargeons le code et mettons à jour l'implémentation dans le gestionnaire.

Optimisation des performances

Au cours du processus de développement, nous sommes souvent confrontés à des problèmes de performances. L'optimisation du code et l'amélioration des performances sont l'une des compétences essentielles des développeurs. Dans fibjs, nous pouvons utiliser CPU Profiler pour nous aider à analyser l'état d'exécution du programme et à optimiser le code.

Dans fibjs, il vous suffit d'utiliser le paramètre de ligne de commande --prof pour démarrer fibjs afin de démarrer le CPU Profiler (l'intervalle par défaut est de 1000 ms). Si vous avez besoin d'une analyse de journal de plus grande précision, vous pouvez utiliser le paramètre --prof-interval pour définir l'intervalle de journalisation. Par exemple:

1 2
$ fibjs --prof test.js # 启动 CPU Profiler,默认以 1000ms 为间隔 $ fibjs --prof --prof-interval=10ms test.js # 启动 CPU Profiler,以 10000us(即 10ms)为间隔

Une fois l'exécution de fibjs terminée, un répertoire de nom de fichier source sera généré dans le répertoire courant. Ce répertoire contient un fichier journal et quelques fichiers auxiliaires. Le nom par défaut du fichier journal est fibjs-xxxx.log, où xxxx est un horodatage. Vous pouvez utiliser l'option --log pour spécifier le nom du fichier journal. À ce stade, vous pouvez --prof-processtraiter les journaux générés en utilisant :

1
fibjs --prof-process fibjs-xxxx.log prof.svg

Une fois l'opération terminée, utilisez le navigateur pour ouvrir prof.svg afin de visualiser le graphique de flamme de ce journal : prof vous pouvez cliquer pour voir l'image en taille réelle. Dans l'image en taille réelle, vous pouvez utiliser la souris pour voir plus de détails. renseignements : prof.svg .

Dans le graphique de flamme généré, chaque bloc de couleur représente un point d'enregistrement. Plus le bloc de couleur est long, plus il est enregistré de fois ; chaque ligne représente une couche de pile d'appels, et plus il y a de couches, plus de couches sont appelées ; appels La pile est placé à l’envers : plus le bloc de couleur est bas, plus la fonction est originale.

Il existe deux types de blocs de couleur, l’un est rouge et l’autre bleu. Dans le profileur fibjs, le rouge représente les opérations JavaScript et le bleu représente les opérations io ou les opérations natives. En fonction du problème que vous devez résoudre, les domaines sur lesquels vous devez vous concentrer varient. Par exemple, si vous devez résoudre le problème d'une utilisation élevée du processeur, vous devez faire attention aux blocs de couleur rouge. Si votre application a une faible utilisation du processeur mais une réponse lente, vous devez faire attention aux blocs de couleur bleus. Plus le bloc de couleur près du haut est grand, plus il nécessite d’attention et d’optimisation.

Nous pouvons essayer d'ajuster les fonctions qui consomment plus de ressources CPU, implémenter les E/S, etc. de manière asynchrone, ou optimiser le code lors de l'écriture.

Déploiement et en ligne

Pour que notre projet fonctionne dans un environnement de production, nous devons le compiler et le déployer. Nous expliquons ici comment utiliser le fichier package.json pour configurer la compilation et le déploiement.

Dans le projet, nous pouvons utiliser package.json pour gérer les dépendances du projet, configurer la compilation et le déploiement. Prenons un simple exemple de package.json :

1 2 3 4 5 6 7
{ "name": "my-project", "version": "1.0.0", "dependencies": { "fib-pool": "^1.0.0" } }

Lorsque nous devons compiler et déployer le projet, il suffit de saisir le répertoire du projet dans le terminal et d'exécuter la commande suivante :

1
fibjs --install

Cette commande installera automatiquement les modules dont dépend le projet. Ensuite, nous pouvons démarrer le projet en utilisant la commande suivante :

1
fibjs app.js

👉【Routage de noms de domaine