为什么我尝试使用 multer 上传文件时 req.file "undefined"?
Why is req.file "undefined" for me when trying to upload a file using multer?
我正在尝试允许用户使用表单上传文件,然后应该在我的控制器文件中使用 multer 处理图像。出于某种原因,当我使用 upload.single('foobar') 时,它返回为“未定义”,并搞砸了我的应用程序的其余部分。具体来说,当我 运行 代码时,我在 createTour.js 文件中的错误处理程序 returns 出现一条警告,内容为“无法读取未定义的 属性 'imageCover'”。任何帮助,将不胜感激。如果有帮助,here's the 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
);
由于您使用的是 multer.single()
,上传的文件将作为对象填充在 req.file
下(参见 https://github.com/expressjs/multer#singlefieldname)。但是,您在这一行中将其作为数组访问:
await sharp(req.file.imageCover[0].buffer)
将其更改为
await sharp(req.file.imageCover.buffer)
应该可以解决这个问题。
同样在客户端,您似乎实际上并未进行 form-data
上传。您需要将其更改为:
const formData = new FormData();
formData.set('imageCover', imageCover);
// add some data from the input fields
formData.set('name', name); // add the other remaining
axios.post('http://127.0.0.1:8000/api/v1/tours', formData, {
headers: {
'content-type': 'multipart/form-data'
}
})
我正在尝试允许用户使用表单上传文件,然后应该在我的控制器文件中使用 multer 处理图像。出于某种原因,当我使用 upload.single('foobar') 时,它返回为“未定义”,并搞砸了我的应用程序的其余部分。具体来说,当我 运行 代码时,我在 createTour.js 文件中的错误处理程序 returns 出现一条警告,内容为“无法读取未定义的 属性 'imageCover'”。任何帮助,将不胜感激。如果有帮助,here's the 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
);
由于您使用的是 multer.single()
,上传的文件将作为对象填充在 req.file
下(参见 https://github.com/expressjs/multer#singlefieldname)。但是,您在这一行中将其作为数组访问:
await sharp(req.file.imageCover[0].buffer)
将其更改为
await sharp(req.file.imageCover.buffer)
应该可以解决这个问题。
同样在客户端,您似乎实际上并未进行 form-data
上传。您需要将其更改为:
const formData = new FormData();
formData.set('imageCover', imageCover);
// add some data from the input fields
formData.set('name', name); // add the other remaining
axios.post('http://127.0.0.1:8000/api/v1/tours', formData, {
headers: {
'content-type': 'multipart/form-data'
}
})