Je travaille sur une application de blog (cliquez sur le lien vers voir le dépôt GitHub ) avec Express , EJS et MongoDB.
Avant de soumettre un nouveau message, bien sûr, je dois valider les entrées du formulaire . J'utilise express-validator version 6.3.0.
Mon contrôleur addPost:
const express = require("express"); const dotenv = require("dotenv"); const mongoose = require("mongoose"); const path = require("path"); const morgan = require("morgan"); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); const expressLayouts = require("express-ejs-layouts"); const flash = require("express-flash"); const session = require("express-session"); const app = express(); dotenv.config(); //Conect to MONGODB mongoose .connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => { console.log("conected"); }); mongoose.connection.on("error", err => { console.log(`DB connection error: ${err.message}`); }); // Set static directory app.use(express.static(path.join(__dirname, "public"))); // Set views directory app.set("views", path.join(__dirname, "views")); // Set view engine app.set("view engine", "ejs"); // Use Express Layouts app.use(expressLayouts); // Morgan Middleware app.use(morgan("dev")); // support parsing of application/json type post data app.use(bodyParser.json()); //support parsing of application/x-www-form-urlencoded post data app.use(bodyParser.urlencoded({ extended: true })); app.use(cookieParser()); // Express Sessions Middleware app.use(session({ secret: '123', resave: true, saveUninitialized: true })); // Express Messages Middleware app.use(flash()); app.use(function (req, res, next) { res.locals.messages = require('express-messages')(req, res); next(); }); // Bring the Dashboard const dashboardRoute = require("./routes/admin/dashboard"); // Get Dashboard Routes app.use('/dashboard', dashboardRoute);
Le modèle Post: p >
<div id="messages" class="text-center"> <% Object.keys(messages).forEach(function (type) { %> <% messages[type].forEach(function (message) { %> <div class="alert alert-<%= type %>"><%= message %></div> <% }) %> <% }) %> </div>
Les messages d'erreur ne sont ni rendus dans la vue, qui ressemble à ceci:
const postSchema = new mongoose.Schema({ title: { type: String, required: true }, short_description: { type: String, required: true }, full_text: { type: String, required: true }, post_image: { type: String, required: false }, updated_at: { type: Date, default: Date.now() }, created_at: { type: Date, default: Date.now() } });
UPDATE: strong >
Le fichier index.js à la racine a ce code:
exports.addPost = (req, res, next) => { // Form validation rules check('title', 'The title field id required') .not() .isEmpty(); check('excerpt', 'The excerpt field id required') .not() .isEmpty(); check('body', 'The full text field id required') .not() .isEmpty(); const errors = validationResult(req); if (!errors.isEmpty()) { console.log(errors.array()); } if (!errors.isEmpty()) { res.render('admin/addpost', { layout: 'admin/layout', website_name: 'MEAN Blog', page_heading: 'Dashboard', page_subheading: 'Add New Post', errors: errors }); req.flash('danger', errors); req.session.save(() => res.redirect('/dashboard')); } else { const post = new Post(); post.title = req.body.title; post.short_description = req.body.excerpt post.full_text = req.body.body; post.save(function(err) { if (err) { console.log(err); return; } else { req.flash('success', "The post was successfully added"); req.session.save(() => res.redirect('/dashboard')); } }); } }
Qu'est-ce que je fais mal?
8 Réponses :
Peut-être devriez-vous commencer par ce https://express-validator.github.io/docs/ puis personnalisez-le progressivement en fonction de vos besoins afin de détecter toute erreur en cours de route.
La version que j'utilise est la version 3.2.1.
Vous effectuez le rendu d'un modèle, vous essayez d'afficher Flash, puis de rediriger. Changez-le en
exports.addPost = (req, res, next) => { // Form validation rules req.check('title').not().isEmpty().withMessage("The title field is mandatory"); req.check('body').not().isEmpty().withMessage("The full text field is mandatory"); const errors = req.validationErrors();
Oubliez le rendu ... Cela n'a aucun sens pour vous de l'avoir là-bas. Ce que fait le rendu, il rend et renvoie un modèle. Par conséquent, votre req.flash et votre redirection ne se produisent jamais ou cela se produit après que l'en-tête a déjà été envoyé.
définition de res.render ():
Rend une vue et envoie la chaîne HTML rendue au client. Paramètres facultatifs:
locals, un objet dont les propriétés définissent des variables locales pour le vue. callback, une fonction de rappel. S'il est fourni, la méthode retourne à la fois l'erreur possible et la chaîne rendue, mais n'effectue pas réponse automatisée. Lorsqu'une erreur se produit, la méthode invoque next (err) en interne.
AND
req.flash('danger', errors); req.session.save(() => res.redirect('/dashboard'));
Les messages de confirmation fonctionnent bien. Les messages d'erreur de validation sont ceux qui ne fonctionnent pas.
Tout d'abord, vous n'avez pas besoin de la redirection et déplacez req.flash au-dessus du rendu
S'il y a des erreurs, ne devrais-je pas restituer le formulaire?
Non, vous appelez req.flash et votre moteur de modèle vérifie s'il y a un message flash et s'il y en a
Fonctionne exactement comme votre succès
De plus, votre validation ne fonctionne pas. Remplacez-le par celui que j'ai écrit
continuons cette discussion dans le chat .
essayez de changer votre instruction if de ceci:
if (!errors.isEmpty()) { return res.send(errors.array()); // can also send an status and catch it // by sending res.status(400).send(errors.array()); }
à ceci:
exports.addPost = (req, res, next) => { // Form validation rules check('title', '<your error message>') .not() .isEmpty(); check('excerpt', '<your error message>') .not() .isEmpty(); check('body', '<your error message>') .not() .isEmpty(); const errors = validationResult(req); const errors = validationResult(req); if (!errors.isEmpty()) { console.log(errors.array()); } }
Modifier
Si vous souhaitez envoyer une réponse à votre front-end, remplacez la commande console.log ()
dans res.send () puis analysez la réponse dans votre front-end
comme ça:
if (!errors.isEmpty()) { console.log('there are no validation errors'); } else { console.log(errors); } }
J'espère que cela a du sens
Bonjour! Avez-vous examiné le dépôt GitHub ? Sinon, veuillez le faire, car cela pourrait être pertinent pour votre réponse. Merci!
Je ger ce long message d'erreur: {title: {ValidatorError: Path
title` est requis.` ....
j'ai mis à jour mon message. Veuillez jeter un autre coup d'oeil. Merci!\
Salut, si vous voulez que les erreurs soient vues dans votre front-end, vous pouvez renvoyer la réponse avec l'erreur spécifique dans le tableau. remplacez simplement le 'console.log' par 'return res.send (errors.array ())' puis analysez-les dans votre front-end
Le modèle contient et doit contenir la variable messages
. La solution ne fonctionne pas.
En fait, return res.send (errors.array ());
entraîne ... une page vierge.
d'après ce que je vois dans la documentation de express-validator vous devez fournir un tableau de règles de validation (ces vérifications
en haut de votre contrôleur) lorsque vous définissez l'itinéraire.
Cela n'a pas beaucoup de sens pour eux d'être en haut du gestionnaire de requêtes car le validateur express ne pourra pas accéder au contexte qui fournit la requête à valider.
Donc, dans le routeur, vous avez besoin de quelque chose comme ceci:
router / front-end / posts.js
exports.addPost = (req, res, next) => { const errors = validationResult(req); if (!errors.isEmpty()) { console.log(errors.array()); } if (!errors.isEmpty()) { res.render('admin/addpost', { layout: 'admin/layout', website_name: 'MEAN Blog', page_heading: 'Dashboard', page_subheading: 'Add New Post', errors: errors }); req.flash('danger', errors); req.session.save(() => res.redirect('/dashboard')); } else { const post = new Post(); post.title = req.body.title; post.short_description = req.body.excerpt post.full_text = req.body.body; post.save(function(err){ if(err){ console.log(err); return; } else { req.flash('success', "The post was successfully added"); req.session.save(() => res.redirect('/dashboard')); } }); } }
controllers / front-end / posts.js
const validationRules = [// Form validation rules check('title', 'The title field id required') .not() .isEmpty(), check('excerpt', 'The excerpt field id required') .not() .isEmpty(), check('body', 'The full text field id required') .not() .isEmpty()]; // create new post router.post('/', validationRules, postsController.addPost);
Tout le reste semble correct, du moins d'après le code que vous avez publié.
N'est-il pas plus logique de valider les données (formulaire) dans le contrôleur? N'est-ce pas "classique"?
Je me demande simplement comment la méthode check
accéderait à la requête, si personne ne l'envoie en tant que paramètre. L'intuition me dit que la validation doit avoir lieu dans un middleware, ajouter une propriété à la requête et transmettre l'exécution au gestionnaire suivant (le contrôleur) où le validationResult (req)
extrait cette propriété créée dans le middleware de validation .
Je ne sais pas. C'est pourquoi j'ai posé la question. Mais je suis presque sûr à 100% qu'il ne devrait y avoir aucune logique dans le fichier des routes sauf la logique des routes.
utilisez ce code dans index.js pour obtenir des messages d'erreur flash localement dans EJS,
app.use(function (req, res, next) { res.locals.messages = req.flash(); next(); });
J'ai ceci comme middleware de messages: app.use (flash ()); app.use (function (req, res, next) {res.locals.messages = require ('express-messages') (req, res); next ();});
. Qu'est-ce qui va pas avec ça? (Cela fonctionne pour les messages de conformation). Où dois-je mettre votre code dans les contextes de mon fichier index.js
(voir qiestion update)?
app.use (flash ()) cela permet d'enregistrer des messages en session express, oui j'ai vu dans index.js. deux options n'itèrent qu'avec des objets d'erreur ou transmettent des messages flash dans les locaux res.locals.messages = req.flash ();
Pouvez-vous mettre votre code dans le code que j'ai pour index.js
? (J'ai essayé de nombreux packages et maintenant je ne sais pas exactement ce que index.js
doit contenir et ce qu'il ne doit pas contenir). Merci!
Dois-je utiliser votre code au lieu de quelle partie de mon code?
ce n'est pas un bogue avec les validateurs express, c'est la façon dont les validateurs fonctionnent dans le cas des middlewares.
Au niveau racine, créez un répertoire appelé utils et à l'intérieur du répertoire un fichier validation.js et ajoutez votre code de validation dedans:
utils / validation.js
Change Line No: 2 From: const { check, validationResult } = require('express-validator'); To: const { validationResult } = require('express-validator'); Remove Line Nos 29 to 39.
Dans les routes / dashboard.js incluent la validation. js
const validator = require('../../utils/validation.js'); Change Line No: 16 From: router.post('/post/add', dashboardController.addPost); To: router.post('/post/add', validator.addPostCheck, dashboardController.addPost);
Dans les contrôleurs / admin / dashboard.js
const { check } = require('express-validator'); exports.addPostCheck = [ check('title', 'The title field id required') .not() .isEmpty(), check('excerpt', 'The excerpt field id required') .not() .isEmpty(), check('body', 'The full text field id required') .not() .isEmpty() ];
J'ai maintenant un [ERR_HTTP_HEADERS_SENT]: Impossible de définir les en-têtes après leur envoi au client dans la console et il n'y a pas de messages d'erreur de validation. Veuillez consulter le code dans le référentiel GitHub .
Cela est dû au numéro de ligne 39 dans controller / dasboard.js, puisque la réponse est renvoyée à partir de la ligne 33, et à nouveau vous essayez de renvoyer la réponse, c'est pourquoi vous obtenez l'erreur [ERR_HTTP_HEADERS_SENT]: Impossible de définir en-têtes après leur envoi au client
. Correction: supprimez la ligne numéro 39.
Résolution du problème "Impossible de définir les en-têtes". Cependant, les messages d'erreur de validation ne s'affichent toujours pas dans la page du formulaire non soumis .
Pour cela, je pense que vous devriez envisager la réponse @TSlegaitis ci-dessus.
Veuillez répondre à cette question aussi. Merci!
<div id="messages" class="text-center"> <% Object.keys(messages).forEach(function (type) { %> <% messages[type].forEach(function (message) { %> <% if (type === 'errors') {%> <div class="alert alert-<%= type %>"><%= message.msg %></div> <%} else { %> <div class="alert alert-<%= type %>"><%= message %></div> <% } %> <% }) %> <% }) %>
Ça a marché! pouvez-vous jeter un œil à cette question < / a> aussi? Merci!
J'ai simplifié votre version du fichier messages.ejs
(à part ça, votre solution est parfaite). Jetez un œil ici . Merci!
J'ai appliqué la solution fournie par Saravanakumar TN avec une petite modification dans messages.ejs .
J'ai: ceci dans le contrôleur:
<div id="messages" class="text-center"> <% Object.keys(messages).forEach(function (type) { %> <% messages[type].forEach(function (message) { %> <div class="alert alert-success <% if (type === 'danger') { %> alert-dismissible <% } %> alert-<%= type %>"> <% if (type === 'danger') { %> <button type="button" class="close" data-dismiss="alert">×</button> <%= message.msg %> <%} else { %> <%= message %> <% } %> </div> <% }) %> <% }) %> </div>
votre tout dernier code est-il poussé vers le dépôt?
@ZeeshanHassanMemon Oui, c'est le cas, vérifiez-le. :)