nodejs Проблемы с enctype = 'multipart / form-data' - PullRequest
0 голосов
/ 02 августа 2020

У меня проблемы с загрузкой изображений с использованием nodejs, express, pug и multer. Я добавил пример локальной библиотеки Mozilla в пример локальной галереи и добавил возможность загрузки изображений. По сути, я получаю сообщение об ошибке, когда включаю enctype = 'multipart / form-data' в свое представление мопса, которое обрабатывает почтовый запрос для формы загрузки изображения. Ниже приведена часть моего кода, вытекающего из определения маршрутов ...

catalog. js

// Require packages.
// const multer = require('multer');
var express = require('express');
var router = express.Router();


// Require our controllers.
var gallery_controller = require('../controllers/galleryController'); 
var author_controller = require('../controllers/authorController');
var tag_controller = require('../controllers/tagController');
var media_controller = require('../controllers/mediaController');

// Require our middleware.
var upload_middleware = require('../middleware/uploadMiddleware');


/// GALLERY ROUTES ///

// GET catalog home page.
router.get('/', gallery_controller.index);  

// GET request for creating a Gallery. NOTE This must come before routes that display Gallery (uses id).
router.get('/gallery/create', gallery_controller.gallery_create_get);

// POST request for creating Gallery.
router.post('/gallery/create', gallery_controller.gallery_create_post);

// GET request to delete Gallery.
router.get('/gallery/:id/delete', gallery_controller.gallery_delete_get);

// POST request to delete Gallery.
router.post('/gallery/:id/delete', gallery_controller.gallery_delete_post);

// GET request to update Gallery.
router.get('/gallery/:id/update', gallery_controller.gallery_update_get);

// POST request to update Gallery.
router.post('/gallery/:id/update', gallery_controller.gallery_update_post);

// GET request for one Gallery.
router.get('/gallery/:id', gallery_controller.gallery_detail);

// GET request for list of all Gallery.
router.get('/galleries', gallery_controller.gallery_list);

/// AUTHOR ROUTES ///

// GET request for creating Author. NOTE This must come before route for id (i.e. display author).
router.get('/author/create', author_controller.author_create_get);

// POST request for creating Author.
router.post('/author/create', author_controller.author_create_post);

// GET request to delete Author.
router.get('/author/:id/delete', author_controller.author_delete_get);

// POST request to delete Author
router.post('/author/:id/delete', author_controller.author_delete_post);

// GET request to update Author.
router.get('/author/:id/update', author_controller.author_update_get);

// POST request to update Author.
router.post('/author/:id/update', author_controller.author_update_post);

// GET request for one Author.
router.get('/author/:id', author_controller.author_detail);

// GET request for list of all Authors.
router.get('/authors', author_controller.author_list);


/// TAG ROUTES ///

// GET request for creating a Tag. NOTE This must come before route that displays Tag (uses id).
router.get('/tag/create', tag_controller.tag_create_get);

// POST request for creating Tag.
router.post('/tag/create', tag_controller.tag_create_post);

// GET request to delete Tag.
router.get('/tag/:id/delete', tag_controller.tag_delete_get);

// POST request to delete Tag.
router.post('/tag/:id/delete', tag_controller.tag_delete_post);

// GET request to update Tag.
router.get('/tag/:id/update', tag_controller.tag_update_get);

// POST request to update Tag.
router.post('/tag/:id/update', tag_controller.tag_update_post);

// GET request for one Tag.
router.get('/tag/:id', tag_controller.tag_detail);

// GET request for list of all Tag.
router.get('/tags', tag_controller.tag_list);


/// MEDIA ROUTES ///

// GET request for creating a Media. NOTE This must come before route that displays Media (uses id).
router.get('/media/create', media_controller.media_create_get);

// POST request for creating Media.
// router.post('/media/create', upload_middleware.uploadFile, media_controller.media_create_post);
// router.post('/media/create', upload_middleware.uploadFile, media_controller.media_create_get);
router.post('/media/create', media_controller.media_create_post);

// GET request to delete Media.
router.get('/media/:id/delete', media_controller.media_delete_get);

// POST request to delete Media.
router.post('/media/:id/delete', media_controller.media_delete_post);

// GET request to update Media.
router.get('/media/:id/update', media_controller.media_update_get);

// POST request to update Media.
router.post('/media/:id/update', media_controller.media_update_post);

// GET request for one Media.
router.get('/media/:id', media_controller.media_detail);

// GET request for list of all Media.
router.get('/media', media_controller.media_list);


module.exports = router;

media_Controller. js

// Require models.
var Media = require('../models/media')
var Gallery = require('../models/gallery')
var async = require('async')

// Require packages.
const { body,validationResult } = require('express-validator/check');
const { sanitizeBody } = require('express-validator/filter');

// Display list of all Medias.
exports.media_list = function(req, res, next) {

  Media.find()
    .populate('gallery')
    .exec(function (err, list_media) {
      if (err) { return next(err); }
      // Successful, so render.
      res.render('media_list', { title: 'Media List', media_list:  list_media});
    })

};

// Display detail page for a specific Media.
exports.media_detail = function(req, res, next) {

    Media.findById(req.params.id)
    .populate('gallery')
    .exec(function (err, media) {
      if (err) { return next(err); }
      if (media==null) { // No results.
          var err = new Error('Gallery copy not found');
          err.status = 404;
          return next(err);
        }
      // Successful, so render.
      res.render('media_detail', { title: 'Gallery:', media:  media});
    })

};

// Display Media create form on GET.
exports.media_create_get = function(req, res, next) {

     Gallery.find({},'title')
    .exec(function (err, galleries) {
      if (err) { return next(err); }
      // Successful, so render.
      res.render('media_form', {title: 'Create Media', gallery_list:galleries } );
    });

};

// Handle Media create on POST.
exports.media_create_post = [
    // Validate fields.
    body('gallery', 'Gallery must be specified').isLength({ min: 1 }).trim(),
    body('name', 'Name must be specified').isLength({ min: 1 }).trim(),
    body('type', 'Type must be specified').isLength({ min: 1 }).trim(),
    body('UMID', 'UMID must be specified').isLength({ min: 1 }).trim(),
    body('created', 'Invalid date').optional({ checkFalsy: true }).isISO8601(),
    
    // Sanitize fields.
    sanitizeBody('gallery').escape(),
    sanitizeBody('name').escape(),
    sanitizeBody('type').escape(),
    sanitizeBody('UMID').escape(),
    sanitizeBody('created').toDate(),
    
    // Process request after validation and sanitization.
    (req, res, next) => {
    
        // Extract the validation errors from a request.
        const errors = validationResult(req);

        // Create a Media object with escaped and trimmed data.
        var media = new Media(
          { gallery: req.body.gallery,
            name: req.body.name,
            type: req.body.type,
            UMID: req.body.UMID,
            created: req.body.created
           });

        if (!errors.isEmpty()) {
            // There are errors. Render form again with sanitized values and error messages.
            Gallery.find({},'title')
                .exec(function (err, galleries) {
                    if (err) { return next(err); }
                    // Successful, so render.
                    res.render('media_form', { title: 'Create Media', gallery_list : galleries, selected_gallery : media.gallery._id , errors: errors.array(), media:media });
            });
            return;
        }
        else {
            // Data from form is valid
            media.save(function (err) {
                // Check is errors.
                console.log('Checking for errors.')
                if (err) { return next(err); }
                
                // Successful - redirect to new record.
                console.log('Successful - redirect to new record.  ' + media.url)
                res.redirect(media.url);
            });
        }
    }
];



// Display Media delete form on GET.
exports.media_delete_get = function(req, res, next) {

    Media.findById(req.params.id)
    .populate('gallery')
    .exec(function (err, media) {
        if (err) { return next(err); }
        if (media==null) { // No results.
            res.redirect('/catalog/media');
        }
        // Successful, so render.
        res.render('media_delete', { title: 'Delete Media', media:  media});
    })

};

// Handle Media delete on POST.
exports.media_delete_post = function(req, res, next) {
    
    // Assume valid Media id in field.
    Media.findByIdAndRemove(req.body.id, function deleteMedia(err) {
        if (err) { return next(err); }
        // Success, so redirect to list of Media items.
        res.redirect('/catalog/media');
        });

};

// Display Media update form on GET.
exports.media_update_get = function(req, res, next) {

    // Get gallery, authors and genres for form.
    async.parallel({
        media: function(callback) {
            Media.findById(req.params.id).populate('gallery').exec(callback)
        },
        galleries: function(callback) {
            Gallery.find(callback)
        },

        }, function(err, results) {
            if (err) { return next(err); }
            if (results.media==null) { // No results.
                var err = new Error('Gallery copy not found');
                err.status = 404;
                return next(err);
            }
            // Success.
            res.render('media_form', { title: 'Update  Media', gallery_list : results.galleries, selected_gallery : results.media.gallery._id, media:results.media });
        });

};

// Handle Media update on POST.
exports.media_update_post = [

    // Validate fields.
    body('gallery', 'Gallery must be specified').isLength({ min: 1 }).trim(),
    body('name', 'Name must be specified').isLength({ min: 1 }).trim(),
    body('type', 'Type must be specified').isLength({ min: 1 }).trim(),
    body('UMID', 'UMID must be specified').isLength({ min: 1 }).trim(),
    body('created', 'Invalid date').optional({ checkFalsy: true }).isISO8601(),
    
    // Sanitize fields.
    sanitizeBody('gallery').escape(),
    sanitizeBody('name').escape(),
    sanitizeBody('type').escape(),
    sanitizeBody('UMID').escape(),
    sanitizeBody('created').toDate(),
    
    // Process request after validation and sanitization.
    (req, res, next) => {

        // Extract the validation errors from a request.
        const errors = validationResult(req);

        // Create a Media object with escaped/trimmed data and current id.
        var media = new Media(
          { gallery: req.body.gallery,
            name: req.body.name,
            type: req.body.type,
            UMID: req.body.UMID,
            created: req.body.created,
            _id: req.params.id
           });

        if (!errors.isEmpty()) {
            // There are errors so render the form again, passing sanitized values and errors.
            Gallery.find({},'title')
                .exec(function (err, galleries) {
                    if (err) { return next(err); }
                    // Successful, so render.
                    res.render('media_form', { title: 'Update Media', gallery_list : galleries, selected_gallery : media.gallery._id , errors: errors.array(), media:media });
            });
            return;
        }
        else {
            // Data from form is valid.
            Media.findByIdAndUpdate(req.params.id, media, {}, function (err,themedia) {
                if (err) { return next(err); }
                   // Successful - redirect to detail page.
                   res.redirect(themedia.url);
                });
        }
    }
];

media_form. мопс

extends layout

block content
  h1=title

  form(method='POST' action='' enctype='multipart/form-data')
    div.form-group
      label(for='gallery') Gallery:
      select#gallery.form-control(type='select', placeholder='Select gallery' name='gallery' required='true' )
        - gallery_list.sort(function(a, b) {let textA = a.title.toUpperCase(); let textB = b.title.toUpperCase(); return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;});
        for gallery in gallery_list
          option(value=gallery._id, selected=(selected_gallery==gallery._id.toString() ? 'selected' : false) ) #{gallery.title}
        
    div.form-group
      label(for='name') Name:
      input#name.form-control(type='text', placeholder='Please enter a name...' name='name' required='true' value=(undefined===media ? '' : media.name) )
        
    div.form-group
      label(for='image') Media:
      input#image.form-control(type='file', placeholder='Please select a media file to upload...' name='image' onchange="readSingleFile(this.files)" )
            
    div.form-group
      label(for='type') Type:
      select#type.form-control(type='select', placeholder='Select a type' name='type' required='true' )
        option(value='BMP' selected=(undefined===media || media.type!='BMP' ? false:'selected')) BMP
        option(value='GIF' selected=(undefined===media || media.type!='GIF' ? false:'selected')) GIF
        option(value='ICO' selected=(undefined===media || media.type!='ICO' ? false:'selected')) ICO
        option(value='JPG' selected=(undefined===media || media.type!='JPG' ? false:'selected')) JPG
        option(value='PNG' selected=(undefined===media || media.type!='PNG' ? false:'selected')) PNG
        option(value='SVG' selected=(undefined===media || media.type!='SVG' ? false:'selected')) SVG
        option(value='WebP' selected=(undefined===media || media.type!='WebP' ? false:'selected')) WebP
        
    div.form-group
      label(for='UMID') UMID:
      input#UMID.form-control(type='text', placeholder='Publisher and date information' name='UMID' required='true' value=(undefined===media ? '' : media.UMID) )
    
    div.form-group
      label(for='created') Date when media was created:
      input#created.form-control(type='date', name='created' value=(undefined===media ? '' : media.created_yyyy_mm_dd))

    button.btn.btn-primary(type='submit') Submit

  if errors 
    ul
      for error in errors
        li!= error.msg

медиа. js

var mongoose = require('mongoose');
var moment = require('moment');

var Schema = mongoose.Schema;

var MediaSchema = new Schema({
    gallery: {type: Schema.ObjectId, ref: 'Gallery', required: true}, // Reference to the associated gallery.
    name:    {type: String, required: true},
    image:   {data: Buffer, contentType: String},
    type:    {type: String, required: true, enum:['BMP', 'GIF', 'ICO', 'JPG', 'PNG', 'SVG', 'WebP'], default:'JPG'},
    UMID:    {type: String, required: true},
    created: {type: Date, default: Date.now},
});

// Virtual for this media object's URL.
MediaSchema
.virtual('url')
.get(function () {
  return '/catalog/media/'+this._id;
});


MediaSchema
.virtual('created_formatted')
.get(function () {
  return moment(this.created).format('MMMM Do, YYYY');
});

MediaSchema
.virtual('created_yyyy_mm_dd')
.get(function () {
  return moment(this.created).format('YYYY-MM-DD');
});


// Export model.
module.exports = mongoose.model('Media', MediaSchema);

приложение. js

// Modules
const compression = require('compression');
const cookieParser = require('cookie-parser');
const createError = require('http-errors');
const express = require('express');
const helmet = require('helmet');
const logger = require('morgan');
const mongoose = require('mongoose');
const path = require('path');


const PATH = './public/uploads';


var app = express();

var catalogRouter = require('./routes/catalog');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');


// Set up mongoose connection
var dev_db_url = 'mongodb://admin:N!md%40@localhost:27017/Gallery';
var mongoDB = process.env.MONGODB_URI || dev_db_url;
mongoose.connect(mongoDB, { useNewUrlParser: true });
mongoose.Promise = global.Promise;
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');


// logger setup
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(helmet());
app.use(compression()); // Compress all routes


// static files
app.use(express.static(path.join(__dirname, 'public')));


// routes.
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Пожалуйста, помогите ???

...