Я пытаюсь разрешить пользователю загружать файл с помощью формы, тогда изображение должно обрабатываться с помощью multer в моем файле контроллера. По какой-то причине, когда я использую upload.single ('foobar'), он возвращается как «undefined» и портит остальную часть моего приложения. В частности, когда я запускаю код, мой обработчик ошибок в файле createTour. js возвращает предупреждение, которое гласит: «Невозможно прочитать свойство 'imageCover' из undefined». Любая помощь будет оценена. Если полезно, вот GitHub .
Вот код файла контроллера (tourController. js):
const multerStorage = multer.memoryStorage();
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('Not an image! Please upload images only.', 400), false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
});
exports.uploadTourImages = upload.single('imageCover');
exports.resizeTourImages = catchAsync(async (req, res, next) => {
console.log(req.file);
req.body.imageCover = `tour-${req.params.id}-${Date.now()}-cover.jpeg`;
await sharp(req.file.imageCover[0].buffer)
.resize(2000, 1333)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/tours/${req.body.imageCover}`);
next();
});
Это форма на передней панели, написано на Jade (create.pug):
extends base
block content
main.main
.create-form
h2.heading-secondary.ma-bt-lg Create a tour, baby!
form.form.form--create
.form__group
label.form__label(for='name') Tour name
input#name.form__input(type='text', placeholder='you@example.com', required)
.form__group
label.form__label(for='duration') Tour duration
input#duration.form__input(type='number', placeholder='you@example.com', required)
.form__group
label.form__label(for='maxGroupSize') Max group size
input#maxGroupSize.form__input(type='number', placeholder='you@example.com', required)
.form__group
label.form__label(for='difficulty') Difficulty
input#difficulty.form__input(type='text', placeholder='you@example.com', required)
.form__group
label.form__label(for='price') Price
input#price.form__input(type='number', placeholder='you@example.com', required)
.form__group
label.form__label(for='startLocation') Starting Location
input#startLocation.form__input(type='text', placeholder='you@example.com')
.form__group
label.form__label(for='summary') Summary
input#summary.form__input(type='text', placeholder='you@example.com', required)
.form__group
label.form__label(for='description') Detailed Description
input#description.form__input(type='text', placeholder='you@example.com', required)
.form__group
input.form__upload(type='file', accept='image/*', id='imageCover', name='imageCover')
label(for='imageCover') Choose image cover
.form__group
button.btn.btn--green Submit
Это код на стороне клиента JS, который обрабатывает данные формы, отправляя их в API (createTour. js):
import axios from 'axios';
import { showAlert } from './alerts';
export const createTour = async (
name,
duration,
maxGroupSize,
difficulty,
price,
startLocation,
summary,
description,
imageCover
) => {
try {
const startLocation = {
type: 'Point',
coordinates: [-80.185942, 25.774772],
address: '47 Bowman Lane, Kings Park, NY 11754',
description: 'New Yorkkkkkkkk'
};
const res = await axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/v1/tours',
data: {
name,
duration,
maxGroupSize,
difficulty,
price,
startLocation,
summary,
description,
imageCover
}
});
if (res.data.status === 'success') {
showAlert('success', 'NEW TOUR CREATED!');
window.setTimeout(() => {
location.assign('/');
}, 1500);
}
} catch (err) {
showAlert('error', err.response.data.message);
}
};
Наконец, не уверен, что это полезно, но это код файла маршрутизатора (tourRoutes. js):
router
.route('/')
.get(tourController.getAllTours)
.post(
authController.protect,
authController.restrictTo('user', 'admin', 'lead-guide'),
tourController.uploadTourImages,
tourController.resizeTourImages,
tourController.createTour
);