Я пытаюсь обновить изображение пользователя, имя и адрес электронной почты, которые отлично работают из бэкэнда, но когда я пробую это из внешнего интерфейса, обновление работает только для имени и электронной почты, но не для изображения, я не могу понять, почему .. .
Вот коды:
Внешний интерфейс
Здесь я отправляю запрос на обновление имени, электронной почты и изображения
const userDataForm = document.querySelector('.profile-update');
if (userDataForm)
userDataForm.addEventListener('submit', async (e) => {
e.preventDefault();
const name = document.getElementById('nameInput').value;
const email = document.getElementById('emailInput').value;
const image = document.getElementById('profile-img-file-input').files[0];
try {
const res = await fetch('/api/v1/users/updateMe', {
method: 'PATCH',
body: JSON.stringify({ name, email, image }),
headers: { 'Content-Type': 'application/json' },
});
console.info(res);
const data = await res.json();
if (data.status == 'success') {
alert('success');
}
} catch (error) {
alert(error);
}
});
profile.ejs
Вот страница ejs
<div class = "profile-user position-relative d-inline-block mx-auto mb-4">
<img
src = "/assets/img/<%= user.photo %>"
id = "user-profile-image"
class = "rounded-circle avatar-xl img-thumbnail user-profile-image"
alt = "user-profile-image"
/>
<div class = "avatar-xs p-0 rounded-circle profile-photo-edit">
<input
id = "profile-img-file-input"
name = "photo"
accept = "image/*"
type = "file"
class = "profile-img-file-input"
/>
<label for = "profile-img-file-input" class = "profile-photo-edit avatar-xs">
<span class = "avatar-title rounded-circle bg-light text-body">
<i class = "ri-camera-fill"></i>
</span>
</label>
</div>
</div>
Внутренний код
Вот контроллер для загрузки изображения и обновления имени, электронной почты и изображения.
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 only images', 400), false);
}
};
// const upload = multer({ dest: 'public/img/users' });
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter,
});
exports.uploadUserPhoto = upload.single('photo');
exports.resizeUserPhoto = catchAsync(async (req, res, next) => {
if (!req.file) return next();
req.file.filename = `user-${req.user.id}-${Date.now()}.jpeg`;
await sharp(req.file.buffer)
.resize(500, 500)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/assets/img/${req.file.filename}`);
next();
});
const filterObj = (obj, ...allowedFields) => {
const newObj = {};
Object.keys(obj).forEach((el) => {
if (allowedFields.includes(el)) newObj[el] = obj[el];
});
return newObj;
};
exports.updateMe = async (req, res, next) => {
// console.info('the filename', req.file);
// console.info(req.body);
// Create an error if a user POSTs password data
if (req.body.password || req.body.passwordConfirm) {
return next(new AppError('This route is not for password update Please use /updateMyPassword', 400));
}
// Update user document
// const user = await User.findById(req.user.id);
// Filterd out unwanted fields that are not allowed to be
// updated
const filteredBody = filterObj(req.body, 'name', 'email');
if (req.file) filteredBody.photo = req.file.filename;
// update the user
const updatedUser = await User.findByIdAndUpdate(req.user._id, filteredBody, {
new: true,
runValidators: true,
});
res.status(200).json({
status: 'success',
data: {
user: updatedUser,
},
});
};
вот файл маршрута
router.patch('/updateMe', userController.uploadUserPhoto, userController.resizeUserPhoto, userController.updateMe);
Спасибо, это помогло мне найти решение
Итак, решение состояло в том, чтобы использовать API данных формы, который позволяет нам отправлять multipart/form-data (что помогает загружать файлы через форму)
эта статья мне тоже помогла https://blog.logrocket.com/multer-nodejs-express-upload-file/
const userDataForm = document.querySelector('.profile-update');
if (userDataForm)
userDataForm.addEventListener('submit', async (e) => {
e.preventDefault();
const form = new FormData();
console.info(form);
form.append('name', document.getElementById('nameInput').value);
form.append('email', document.getElementById('emailInput').value);
form.append('photo', document.getElementById('profile-img-file-input').files[0]);
console.info(form);
try {
const res = await fetch('/api/v1/users/updateMe', {
method: 'PATCH',
body: form,
});
console.info(res);
const data = await res.json();
console.info(data);
console.info(form);
if (data.status == 'success') {
showAlert('success', 'Profile successfully updated');
window.location.reload();
}
} catch (error) {
alert(error);
}
});
Вы не можете помещать двоичные файлы (например, изображения) в JSON вот так.
multer
не работает с JSON, он работает сmultipart/form-data
, который вы должны использовать вместо JSON.