每当用户要上传图像时,我都会遇到UnhandledPromiseRejectionWarning: ValidationError validation failed: imageUrl: Path
imageUrl is required
,但是当我在imageUrl部分下的模型文件上删除/注释required: true
关键字时,我可以提交帖子,但是图像不会上传到文件系统上,并且不会渲染,因此我只会看到提交帖子的标题和详细信息,我的开发环境是
Debian 9.9, express": "^4.17.1, multer": "^1.4.0, mongoose": "^5.6.3, MongoDB v4.0.11, node v10.16.1 listed below is my code from app.js, model.js, routes.js and add.handlebars(view)
。您的帮助非常有用
app.js
const express = require('express');
const path = require('path');
const exphbs = require('express-handlebars');
const methodOverride = require('method-override');
const flash = require('connect-flash');
const session = require('express-session');
const bodyParser = require('body-parser');
const passport = require('passport');
const mongoose = require('mongoose');
const multer = require('multer');
const MongoDBStore = require('connect-mongodb-session')(session);
//const app = express();
// Load routes
const ideas = require('./routes/ideas');
const users = require('./routes/users');
// Passport Config
require('./config/passport')(passport);
// DB Config
const db = require('./config/database');
// Map global promise - get rid of warning
mongoose.Promise = global.Promise;
// Connect to mongoose
mongoose.connect(db.mongoURI, {
useNewUrlParser: true
})
.then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err));
// image handling on db
const app = express();
const store = new MongoDBStore({
uri: db.mongoURI,
collection: 'sessions'
});
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
// Handlebars Middleware
app.engine('handlebars', exphbs({
defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Static folder
app.use(
multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/images', express.static(path.join(__dirname, 'images')));
// Method override middleware
app.use(methodOverride('_method'));
// Express session midleware
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// Global variables
app.use(function(req, res, next){
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
// Index Route
app.get('/', (req, res) => {
const title = 'Welcome';
res.render('index', {
title: title
});
});
// About Route
app.get('/about', (req, res) => {
res.render('about');
});
// Use routes
app.use('/ideas', ideas);
app.use('/users', users);
const port = process.env.PORT || 5000;
app.listen(port, () =>{
console.log(`Server started on port ${port}`);
});
对于我的模型,为防万一,我下面分别列出了两个文件Idea.js和User.js
models / Idea.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const IdeaSchema = new Schema({
title:{
type: String,
required: true
},
imageUrl: {
type: String,
required: true
},
details:{
type: String,
required: true
},
user:{
type: String,
required:true
},
date: {
type: Date,
default: Date.now
}
});
mongoose.model('ideas', IdeaSchema);
models / User.js(以防万一)
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
password:{
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
mongoose.model('users', UserSchema);
,对于该路线,我分别在下面发布了两个文件idea.js和users.js
route / ideas.js
const express = require('express');
const mongoose = require('mongoose');
const router = express.Router();
const {ensureAuthenticated} = require('../helpers/auth');
// Load Idea Model
require('../models/Idea');
const Idea = mongoose.model('ideas');
// Idea Index Page
router.get('/', ensureAuthenticated, (req, res) => {
Idea.find({user: req.user.id})
.sort({date:'desc'})
.then(ideas => {
res.render('ideas/index', {
ideas:ideas
});
});
});
// Add Idea Form
router.get('/add', ensureAuthenticated, (req, res) => {
res.render('ideas/add');
});
// Edit Idea Form
router.get('/edit/:id', ensureAuthenticated, (req, res) => {
Idea.findOne({
_id: req.params.id
})
.then(idea => {
if(idea.user != req.user.id){
req.flash('error_msg', 'Not Authorized');
res.redirect('/ideas');
} else {
res.render('ideas/edit', {
idea:idea
});
}
});
});
// Process Form
router.post('/', ensureAuthenticated, (req, res) => {
let errors = [];
if(!req.body.title){
errors.push({text:'Please add a title'});
}
if(!req.body.details){
errors.push({text:'Please add some details'});
}
if(errors.length > 0){
res.render('/add', {
errors: errors,
title: req.body.title,
details: req.body.details
});
} else {
const newUser = {
title: req.body.title,
details: req.body.details,
user: req.user.id
}
new Idea(newUser)
.save()
.then(idea => {
req.flash('success_msg', 'Video idea added');
res.redirect('/ideas');
})
}
});
// Edit Form process
router.put('/:id', ensureAuthenticated, (req, res) => {
Idea.findOne({
_id: req.params.id
})
.then(idea => {
// new values
idea.title = req.body.title;
idea.details = req.body.details;
idea.save()
.then(idea => {
req.flash('success_msg', 'Video idea updated');
res.redirect('/ideas');
})
});
});
// Delete Idea
router.delete('/:id', ensureAuthenticated, (req, res) => {
Idea.remove({_id: req.params.id})
.then(() => {
req.flash('success_msg', 'Video idea removed');
res.redirect('/ideas');
});
});
module.exports = router;
users.js
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const passport = require('passport');
const router = express.Router();
// Load User Model
require('../models/User');
const User = mongoose.model('users');
// User Login Route
router.get('/login', (req, res) => {
res.render('users/login');
});
// User Register Route
router.get('/register', (req, res) => {
res.render('users/register');
});
// Login Form POST
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect:'/ideas',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
// Register Form POST
router.post('/register', (req, res) => {
let errors = [];
if(req.body.password != req.body.password2){
errors.push({text:'Passwords do not match'});
}
if(req.body.password.length < 4){
errors.push({text:'Password must be at least 4 characters'});
}
if(errors.length > 0){
res.render('users/register', {
errors: errors,
name: req.body.name,
email: req.body.email,
password: req.body.password,
password2: req.body.password2
});
} else {
User.findOne({email: req.body.email})
.then(user => {
if(user){
req.flash('error_msg', 'Email already regsitered');
res.redirect('/users/register');
} else {
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
newUser.password = hash;
newUser.save()
.then(user => {
req.flash('success_msg', 'You are now registered and can log in');
res.redirect('/users/login');
})
.catch(err => {
console.log(err);
return;
});
});
});
}
});
}
});
// Logout User
router.get('/logout', (req, res) => {
req.logout();
req.flash('success_msg', 'You are logged out');
res.redirect('/users/login');
});
module.exports = router;
和我的视图/添加视图
<div class="card card-body">
<h3>Video Idea</h3>
<form action="/ideas" method="post">
<div class="form-group">
<label for="title">Title</label>
<input type="text" class="form-control" name="title" required>
</div>
<div class="form-control">
<label for="image">Image</label>
<input
type="file"
name="image"
id="image" >
</div>
<div class="form-group">
<label for="details">Details</label>
<textarea class="form-control" name="details" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
答案 0 :(得分:1)
您忘记了从图像输入中提取值。
首先,穆勒使用multipart/form-data
形式的表单,即:
<form action="/ideas" method="post" enctype="multipart/form-data">
...
一旦您进行了编辑,便可以在route/ideas.js
中的中间件中检查并提取
title: req.body.title,
details: req.body.details
也检查并提取图像输入,即:
imageUrl: req.file.path