Maison >interface Web >js tutoriel >Créez un site Web MVC complet avec express
Express est l'un des meilleurs frameworks pour Node.js. Il a un excellent soutien et un tas de fonctionnalités utiles. Il y a beaucoup de grands articles, qui couvrent toutes les bases. Cependant, cette fois, je veux creuser un peu plus et partager mon flux de travail pour créer un site Web complet. En général, cet article est non seulement pour Express, mais pour l'utiliser en combinaison avec d'autres excellents outils disponibles pour les développeurs de nœuds.
Pour suivre ce tutoriel, je suppose que vous êtes un peu familier avec le nœud et que vous l'avez déjà installé sur votre système.
Au cœur de l'Express est connect. Il s'agit d'un cadre middleware, qui est livré avec beaucoup de choses utiles. Si vous vous demandez ce qu'est exactement le middleware, voici un exemple rapide:
const Connect = require ('connect'),<br> http = require ('http');<br><br> const app = connect ()<br> .Use (fonction (req, res, suivant) {<br> console.log ("c'est mon premier middleware");<br> suivant();<br> })<br> .Use (fonction (req, res, suivant) {<br> console.log ("c'est mon deuxième middleware");<br> suivant();<br> })<br> .Use (fonction (req, res, suivant) {<br> console.log ("end");<br> res.end ("Hello World");<br> });<br><br> http.createServer (app) .Listen (3000);<br>
Le middleware est essentiellement une fonction qui accepte les objets de réponse et un objet de réponse ou passer le flux à la fonction suivante en appelant l'appel de méthode suivant () dans le deuxième middleware, le corps analyseur analyse les corps de demande et prend en charge l'application / json, l'application / x-www-forlencoded, et multipart / form-data. Et req.cookies avec un objet clé par le nom du cookie.
Express enveloppe en fait Connect et ajoute de nouvelles fonctionnalités autour de lui, comme la logique de routage, ce qui rend le processus beaucoup plus fluide. Voici un exemple de gestion d'une demande de GET dans Express:
app.get ('/ hello.txt', fonction (req, res) {<br> var body = 'Hello World';<br> res.sethEader («Content-Type», «Text / Plain»);<br> res.sethEader («Content-Length», body.length);<br> res.end (corps);<br> });<br>
Le code source de cet exemple de site que nous avons construit est disponible sur GitHub. N'hésitez pas à le débarrasser et à jouer avec. Voici les étapes pour exécuter le site.
{<br> "nom": "mywebsite",<br> "Description": "Mon site",<br> "Version": "0.0.1",<br> "dépendances": {<br> "Express": "5.x"<br> }<br> }<br>
Le code du cadre sera placé dans Node_Modules , et vous pourrez en créer une instance. Cependant, je préfère une autre option, en utilisant l'outil de ligne de commande. En utilisant la commande NPX Express-Generator:
Utilisation: express [options] [dir]<br><br> Options:<br><br> - Version Sortie Le numéro de version<br> -e, --ejs Ajouter une prise en charge du moteur EJS<br> - PUG Ajouter une prise en charge du moteur PUG<br> - HBS Ajouter la prise en charge du moteur du guidon<br> -H, - Hogan Ajouter la prise en charge du moteur hogan.js<br> -v, --View <neord> Ajouter la prise en charge de la vue <dine> (poussière | EJS | HBS | HJS | JADE | PUG | BIGH | VASH) (par défaut à Jade)<br> --No-View Utilisez le HTML statique au lieu du moteur de vue<br> -C, --CSS <deger> Ajouter un support de feuille de style <moteur> (moins | stylet | Compasse | Sass) (par défaut en css simple)<br> --git ajouter .gitignore<br> -F, - Force Force on Non vicine répertoire<br> -H, - Help Informations d'utilisation de sortie<br></moteur></deger></dine></neord>
Comme vous pouvez le voir, il n'y a que quelques options disponibles, mais pour moi, elles suffisent. Normalement, j'utilise moins comme préprocesseur CSS et guidon comme moteur de modèles. Dans cet exemple, nous aurons également besoin d'une prise en charge de la session, de sorte que l'installation NPM et un dossier Node_modules apparaîtront.
Je me rends compte que l'approche ci-dessus n'est pas toujours appropriée. Vous voudrez peut-être placer vos gestionnaires d'itinéraire dans un autre répertoire ou quelque chose de similaire. Mais, comme vous le verrez dans les prochaines sections, je vais apporter des modifications à la structure qui est déjà générée, et c'est assez facile à faire. Vous devriez donc simplement penser à l'application.js pour travailler avec notre nouvelle structure de fichiers. Nous devons supprimer ces deux lignes:
const usersrouter = require ("./ routes / utilisateurs");<br> ...<br> app.use ("/ utilisateurs", utilisateur);<br>
Maintenant, nous devons configurer la configuration. Imaginons que notre petit site doit être déployé à trois endroits différents: un serveur local, un serveur de mise en scène et un serveur de production. Bien sûr, les paramètres de chaque environnement sont différents, et nous devons mettre en œuvre un mécanisme suffisamment flexible. Comme vous le savez, chaque script de nœud est exécuté en tant que programme de console. Nous pouvons donc facilement envoyer des arguments en ligne de commande qui définiront l'environnement actuel. J'ai enveloppé cette partie dans un module séparé afin d'écrire un test pour cela plus tard. Voici le fichier /config/index.js :
const config = {<br> locale: {<br> Mode: «local»,<br> Port: 3000<br> },<br> Staging: {<br> Mode: «mise en scène»,<br> Port: 4000<br> },<br> production: {<br> Mode: «production»,<br> Port: 5000<br> }<br> }<br> module.exports = fonction (mode) {<br> return config [mode || process.argv [2] || 'local'] || config.local;<br> }<br>
Il n'y a que deux paramètres (pour l'instant): port. Comme vous l'avez peut-être deviné, l'application utilise différents ports pour les différents serveurs. C'est pourquoi nous devons mettre à jour le point d'entrée du site dans app.js.
const config = require ('./ config') ();<br> process.env.port = config.port;<br>
Pour basculer entre les configurations, ajoutez simplement l'environnement à la fin. Par exemple:
stadification du NPM Start<br>
Exécutera le serveur au port 4000.
Maintenant, nous avons tous nos paramètres en un seul endroit, et ils sont facilement gérables.
Je suis un grand fan du développement axé sur les tests (TDD). Je vais essayer de couvrir toutes les classes de base utilisées dans cet article. Bien sûr, avoir des tests pour absolument tout ferait que cette écriture serait trop longue, mais en général, c'est ainsi que vous devez procéder lors de la création de vos propres applications. L'un de mes frameworks préférés pour les tests est UVU, car il est très facile à utiliser et rapide. Bien sûr, il est disponible dans le registre NPM:
Installation du NPM - Save-Dev UVU<br>
Ensuite, créez un nouveau script à l'intérieur du test NPM et vous devriez voir ce qui suit:
config.js<br> • • • (3/3)<br><br> Total: 3<br> Passé: 3<br> Sauté: 0<br> Durée: 0,81 ms<br>
Cette fois, j'ai écrit la mise en œuvre en premier et le test deuxième. Ce n'est pas exactement la façon TDD de faire les choses, mais au cours des prochaines sections, je ferai le contraire.
Je recommande fortement de passer beaucoup de temps à écrire des tests. Il n'y a rien de mieux qu'une application entièrement testée.
Il y a quelques années, j'ai réalisé quelque chose de très important, ce qui peut vous aider à produire de meilleurs programmes. Chaque fois que vous commencez à écrire une nouvelle classe, un nouveau module ou simplement une nouvelle logique, demandez-vous:
Comment puis-je tester cela?
La réponse à cette question vous aidera à coder beaucoup plus efficacement, à créer de meilleures API et à tout mettre dans des blocs bien séparés. Vous ne pouvez pas rédiger des tests pour le code spaghetti. Par exemple, dans le fichier de configuration ci-dessus ( /config/index.js ), j'ai ajouté la possibilité d'envoyer la configuration de production, mais le script de nœud est exécuté avec un NPM Install MongoDB.
Ensuite, nous allons rédiger un test, qui vérifie s'il y a un serveur MongoDB en cours d'exécution. Voici le fichier /tests/mongodb.js :
const {test} = require ("uvu");<br> const {MongoClient} = require ("MongoDB");<br><br> TEST ("MONGODB Server Active", Fonction Async () {<br> const Client = new Mongoclient ("MongoDB: //127.0.0.1: 27017 / FastDelivery");<br> attendre client.connect ();<br> });<br><br> test.run ();<br><br>
Nous n'avons pas besoin d'ajouter une méthode .Connect du client MongoDB reçoit un objet mongoclient chaque fois que nous devons faire une demande à la base de données. Pour cette raison, nous devons nous connecter à la base de données dans la création de serveurs initiaux. Pour ce faire, dans la propriété req.db disponible, en raison du middleware fonctionnant automatiquement avant chaque demande.
Nous connaissons tous le modèle MVC. La question est de savoir comment cela s'applique à l'exprimer. Plus ou moins, c'est une question d'interprétation. Dans les prochaines étapes, je créerai des modules, qui agissent comme un modèle, une vue et un contrôleur.
Le modèle est ce qui gérera les données qui se trouvent dans notre application. Il devrait avoir accès à un Mongoclient. Notre modèle devrait également avoir une méthode pour l'extension, car nous pouvons vouloir créer différents types de modèles. Par exemple, nous pourrions vouloir un ContactsModel. Nous devons donc écrire une nouvelle spécification, /tests/base.model.js , afin de tester ces deux fonctionnalités du modèle. Et rappelez-vous, en définissant ces fonctionnalités avant de commencer à codager l'implémentation, nous pouvons garantir que notre module ne fera que ce que nous voulons qu'il fasse.
const {test} = require ("uvu");<br> const assert = require ("uvu / assert");<br> const ModelClass = require ("../ Modèles / base");<br> const dbmockup = {};<br> test ("Création du module", fonction asynchrone () {<br> const Model = new ModelClass (dbmockup);<br> assert.ok (modèle.db);<br> assert.ok (Model.SetDB);<br> assert.ok (modèle.collection);<br> });<br> test.run ();<br>
Au lieu d'un véritable objet DB et d'un répertoire de vues de vues de base de données sera modifié en classe de vue de base. Ce petit changement nécessite maintenant un autre changement. Nous devons informer Express que nos fichiers de modèle sont maintenant placés dans un autre répertoire:
app.set ("vues", path.join (__ dirname, "modèles"));<br>
Tout d'abord, je vais définir ce dont j'ai besoin, écrire le test, puis écrire l'implémentation. Nous avons besoin d'un module correspondant aux règles suivantes:
const data = {développeur: "Krasimir tSonev"};<br> Response.ContentType ("Application / JSON");<br> Response.Send (JSON.Stringify (données));<br>
Au lieu de le faire à chaque fois, il serait bien d'avoir une classe JSONView, ou même un répertoire de tests, et si vous exécutez '/' après l'itinéraire - qui, dans l'exemple ci-dessus, est en fait le contrôleur - est juste une fonction de middleware qui accepte la réponse, et Express (1) l'outil de ligne de commande crée une méthode de répertoire nommé Run, qui est l'ancienne fonction middleware
OK, nous avons un bon ensemble de cours pour notre architecture MVC, et nous avons couvert nos modules nouvellement créés avec des tests. Maintenant, nous sommes prêts à continuer le site de notre fausse entreprise, FastDelivery.
Imaginons que le site dispose de deux parties: un frontal et un panneau d'administration. L'enju frontal sera utilisé pour afficher les informations écrites dans la base de données à nos utilisateurs finaux. Le panneau d'administration sera utilisé pour gérer ces données. Commençons par notre panneau Admin (Control).
Créons d'abord un contrôleur simple qui servira de page d'administration. Voici le fichier /routes/admin.js :
const baseController = requis ("./ base"),<br> View = require ("../ vues / base");<br> module.exports = new (classe AdminController étend BaseController {<br> constructeur () {<br> super ("admin");<br> }<br> run (req, res, suivant) {<br> if (this.authorize (req)) {<br> req.Session.fastDelivery = true;<br> req.Session.save (fonction (err) {<br> var v = nouvelle vue (res, "admin");<br> v.render ({<br> Titre: "Administration",<br> Contenu: "Bienvenue dans le panneau de commande",<br> });<br> });<br> } autre {<br> const v = nouvelle vue (res, "admin-login");<br> v.render ({<br> Titre: "Veuillez vous connecter",<br> });<br> }<br> }<br> Autoriser (req) {<br> retour (<br> (REQ.SESSION &&<br> req.Session.fastDelivery &&<br> req.Session.fastDelivery === true) ||<br> (req.body &&<br> req.body.username === this.userName &&<br> req.body.password === this.password)<br> ));<br> }<br> }) ();<br>
En utilisant les classes de base pré-écrites pour nos contrôleurs et nos vues, nous pouvons facilement créer le point d'entrée du panneau de configuration. La méthode admin.Run directement comme middleware. C'est parce que nous voulons garder le contexte. Si nous faisons ceci:
app.all ('/ admin *', admin.run);<br>
Le mot administrateur pointera quelque chose d'autre.
Chaque page qui commence par / admin doit être protégée. Pour y parvenir, nous allons utiliser le middleware: Session d'Express. Il attache simplement un objet à la demande appelée contrôleur d'administration pour faire deux choses supplémentaires:
Voici une petite fonction d'assistance que nous pouvons utiliser pour accomplir ceci:
Autoriser (req) {<br> retour (<br> (REQ.SESSION &&<br> req.Session.fastDelivery &&<br> req.Session.fastDelivery === true) ||<br> (req.body &&<br> req.body.username === this.userName &&<br> req.body.password === this.password)<br> ));<br> }<br>
Tout d'abord, nous avons une déclaration qui essaie de reconnaître l'utilisateur via l'objet de session. Deuxièmement, nous vérifions si un formulaire a été soumis. Si c'est le cas, les données du formulaire sont disponibles dans le middleware BodyParser. Ensuite, nous vérifions simplement si le nom d'utilisateur et le mot de passe correspondent.
Et maintenant, voici le titre, l'image et la propriété Type détermineront le propriétaire de l'enregistrement. Par exemple, la page Contacts n'aura besoin que d'un seul enregistrement avec le contrôleur d'administration devra être beaucoup modifié. Pour simplifier la tâche, j'ai décidé de combiner la liste des enregistrements ajoutés et le formulaire pour les ajouter / les modifier. Comme vous pouvez le voir dans la capture d'écran ci-dessous, la partie gauche de la page est réservée à la liste et à la bonne partie du formulaire.
Avoir tout sur une page signifie que nous devons nous concentrer sur la partie qui rend la page ou, pour être plus spécifique, sur les données que nous envoyons au modèle. C'est pourquoi j'ai créé plusieurs fonctions d'assistance qui sont combinées, comme ainsi:
this.del (req, function () {<br> this.form (req, res, function (formmarkup) {<br> this.list (function (listmarkup) {<br> v.render ({<br> Titre: "Administration",<br> Contenu: "Bienvenue dans le panneau de commande",<br> Liste: listMarkup,<br> Formulaire: formulaire,<br> });<br> });<br> });<br> });<br> const v = nouvelle vue (res, "admin");<br>
Ça a l'air un peu moche, mais ça marche comme je le voulais. Le premier assistant est une action = delete & id = [id de l'enregistrement], il supprime les données de la collection. La deuxième fonction est appelée la méthode de liste récupère les informations et prépare une table HTML, qui est ensuite envoyée au modèle. L'implémentation de ces trois aides se trouve dans le code source de ce tutoriel.
Ici, j'ai décidé de vous montrer la fonction qui gère le téléchargement de fichiers dans admin.js :
handleFileUpload (req) {<br> if (! req.files ||! req.files.picture ||! req.files.picture.name) {<br> return req.body.currentPicture || "";<br> }<br> const data = fs.readfilesync (req.files.pictture.path);<br> const filename = req.files.pictture.name;<br> const uid = crypto.randombytes (10) .toString ("hex");<br> const dir = __dirname "/../public/uploads/" uid;<br> fs.mkDirsync (dir, "0777");<br> fs.writeFileSync (dir "/" nom de fichier, données);<br> return "/ uploads /" uid "/" filename;<br> }<br>
Si un fichier est soumis, le script de nœud req.files.picture. Dans l'extrait de code ci-dessus, readFilesYNC, writeFileSync.
Le travail acharné est maintenant terminé. Le panneau d'administration fonctionne et nous avons une maison et quatre enregistrements avec un type d'objet DB sur le blog, mais appelez Différent / Blog /: ID String. Cet itinéraire correspondra aux URL comme req.params.id. En d'autres termes, nous pouvons définir des paramètres dynamiques. Dans notre cas, c'est l'identification du disque. Une fois que nous avons ces informations, nous pouvons créer une page unique pour chaque article.
La deuxième partie intéressante est la façon dont j'ai construit les pages des services, des carrières et des contacts. Il est clair qu'ils n'utilisent qu'un seul enregistrement de la base de données. Si nous devions créer un contrôleur différent pour chaque page, nous devions copier / coller le même code et simplement modifier le type dans sa commande d'installation NPM devrait être exécuté afin d'installer les nouvelles dépendances (le cas échéant).
Gardez à l'esprit que le nœud est encore assez jeune, donc tout ne peut pas fonctionner comme vous vous y attendez, mais il y a des améliorations apportées tout le temps. Par exemple, vous garantit toujours que votre programme Node.js fonctionnera en continu. Vous pouvez le faire en émettant la commande suivante:
Commencez pour toujours votreapp.js<br>
C'est aussi ce que j'utilise sur mes serveurs. C'est un joli petit outil, mais il résout un gros problème. Si vous exécutez votre application avec pour toujours, il suffit de redémarrer l'application.
Maintenant, je ne suis pas un administrateur système, mais je voulais partager mon expérience d'intégration des applications de nœuds avec Apache ou Nginx parce que je pense que cela fait partie du flux de travail de développement.
Comme vous le savez, Apache s'exécute normalement sur le port 80, ce qui signifie que si vous ouvrez http: // localhost: 80, vous verrez une page desservie par votre serveur Apache, et très probablement votre script de nœud écoute sur un autre port. Vous devez donc ajouter un hôte virtuel qui accepte les demandes et les envoie au bon port. Par exemple, disons que je souhaite héberger le site que nous venons de construire sur mon serveur Apache local sous le fichier hôte.
127.0.0.1 Expresscompletewebsite.dev<br>
Après cela, nous devons modifier le fichier httpd-vhosts.conf dans le répertoire de configuration Apache et ajouter:
# expresscompletewebsite.dev<br> <virtualhost><br> Servername expressCLEPleTewebsite.dev<br> Serveralias www.expresscompletewebsite.dev<br> Proxyréquest<br> <proxy><br> Commander nier, permettez<br> Autoriser de tous<br> Proxy><br> <emplacement></emplacement><br> Proxypass http: // localhost: 3000 /<br> Proxypassreverse http: // localhost: 3000 /<br> <br> Virtualhost><br></proxy></virtualhost>
Le serveur accepte toujours les demandes sur le port 80 mais les transmet au port 3000, où le nœud écoute.
La configuration Nginx est beaucoup plus facile et, pour être honnête, c'est un meilleur choix pour héberger des applications basées sur Node.js. Vous devez toujours ajouter le nom de domaine dans votre fichier d'hôtes . Après cela, créez simplement un nouveau fichier dans le répertoire / sites compatible avec les sites sous l'installation Nginx. Le contenu du fichier ressemblerait à ceci:
serveur {<br> Écoutez 80;<br> server_name expresscompletewebsite.dev<br> emplacement / {<br> proxy_pass http://127.0.0.1:3000;<br> proxy_set_header host $ http_host;<br> }<br> }<br>
Gardez à l'esprit que vous ne pouvez pas exécuter Apache et Nginx avec la configuration des hôtes ci-dessus. En effet, ils nécessitent tous les deux le port 80. De plus, vous pouvez faire un peu de recherches supplémentaires sur une meilleure configuration de serveur si vous prévoyez d'utiliser les extraits de code ci-dessus dans un environnement de production. Comme je l'ai dit, je ne suis pas un expert dans ce domaine.
Express est un excellent cadre, ce qui vous donne un bon point de départ pour commencer à construire vos applications. Comme vous pouvez le voir, c'est une question de choix sur la façon dont vous allez l'étendre et ce que vous utiliserez pour construire avec. Il simplifie les tâches ennuyeuses en utilisant un excellent middleware et laisse les pièces amusantes au développeur.
Ce message a été mis à jour avec les contributions de Jacob Jackson. Jacob est développeur Web, écrivain technique, pigiste et contributeur open-source.
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!