html - 即使在使用 Multer 和 HTML 的 Nodejs 项目中表单提交失败时,图像也会保存
问题描述
我正在开发一个 Nodejs 项目,目前正试图弄清楚如何防止在表单提交失败时保存通过表单上传的图像(即由于空字段)。我查看了其他几篇其他帖子、Google 和 multer 文档,但无法弄清楚如何阻止上传发生。这是我的仓库的代码:https ://github.com/halsheik/RecipeWarehouse.git 。下面,我发布了任何相关代码。谢谢你的帮助。
// Modules required to run the application
const express = require('express');
const multer = require('multer');
const crypto = require('crypto');
const path = require('path');
const { ensureAuthenticated } = require('../config/auth');
// Creates 'mini app'
const router = express.Router();
// Models
const Recipe = require('../models/Recipe'); // Recipe Model
// Set up storage engine
const storage = multer.diskStorage({
destination: function(req, file, callback){
callback(null, 'public/uploads');
},
filename: function(req, file, callback){
crypto.pseudoRandomBytes(16, function(err, raw) {
if (err) return callback(err);
callback(null, raw.toString('hex') + path.extname(file.originalname));
});
}
});
const upload = multer({
storage: storage
});
// My Recipes
router.get('/myRecipes', ensureAuthenticated, function(req, res){
Recipe.find({}, function(err, recipes){
if(err){
console.log(err);
} else {
res.render('./home/myRecipes', {
recipes: recipes
});
}
});
});
// My Recipes
router.get('/createRecipe', ensureAuthenticated, function(req, res){
res.render('./home/createRecipe');
});
// Create Recipe
router.post('/createRecipe', ensureAuthenticated, upload.single('recipeImage'), function(req, res){
const { recipeName, recipeDescription, ingredients, directions } = req.body;
let errors = [];
// Checks that all fields are not empty
if(!recipeName || !recipeDescription || !ingredients || !directions){
errors.push({ msg: 'Please fill in all fields.' });
}
// Checks that an image is uploaded
if(!req.file){
errors.push({ msg: 'Please add an image of your recipe' });
}
// Checks for any errors and prevents recipe creation if any
if(errors.length > 0){
// Displays create Recipe form along with errors
res.render('./home/createRecipe', {
errors
});
} else {
// Create a new 'Recipe' using our model
const newRecipe = new Recipe({
recipeName: recipeName,
author: req.user._id,
recipeImageFileName: req.file.filename,
recipeDescription: recipeDescription,
ingredients: ingredients,
directions: directions,
});
// Saves recipe to mongoDB database
newRecipe.save().then(function(){
res.redirect('/recipes/myRecipes');
}).catch(function(err){
console.log(err);
});
}
});
// Get Single Recipe
router.get('/:id', function(req, res){
// Searches for a 'Recipe' with a unique 'id'
Recipe.findById(req.params.id, function(err, recipe){
if(err){
throw err;
}
// Renders the Recipe in its own page with full information
res.render('./home/recipe.ejs', {
recipe: recipe
});
});
});
// Delete recipe
router.delete('/:id', function(req, res){
const query = {_id: req.params.id}
Recipe.deleteOne(query, function(err){
if(err){
console.log(err);
throw err;
}
res.send('Success');
});
});
module.exports = router;
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Homemade</title>
<!-- Required program scripts -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<!-- Style Sheets-->
<link rel="stylesheet" href="/styles/navBarStyle.css">
<link rel="stylesheet" href="/styles/myRecipesStyle.css">
<link rel="stylesheet" href="/styles/createRecipeStyle.css">
</head>
<body>
<!-- Background image -->
<img id="background" src="/images/foodBackground.jpg" alt="">
<div id="newRecipeContainer">
<div id="closeButtonContainer">
<div id="backButton"><a id="back" href="/recipes/myRecipes">← My Recipes</a></div>
</div>
<form id="createRecipeForm" action="/recipes/createRecipe" method="POST" enctype="multipart/form-data">
<label id="formSubHeading">Create Your Homemade Recipe</label>
<div id="recipeNameContainer">
<label id="recipeNameLabel">Title</label>
<input id="recipeNameInput" type="text" name="recipeName">
</div>
<div id="recipeImage">
<label id="recipeImageLabel">Add An Image of Your Meal</label>
<input id="recipeImageInput" type="file" accept="image/*" name="recipeImage"/>
<label id="recipeImageInputLabel" for="recipeImageInput" name="recipeImage">Choose A File</label>
</div>
<div id="recipeDescription">
<label id="recipeDescriptionLabel">Description</label>
<textarea id="recipeDescriptionInput" name="recipeDescription" cols="30" rows="10" maxlength="2000"></textarea>
</div>
<div class="ingredientsContainer">
<label id="ingredientsLabel">Ingredients</label>
<button id="addIngredientButton" type="button" @click="addIngredientForm">Add Another Ingredient</button>
<div class="allIngredients" v-for="(ingredient, ingredientIndex) in ingredients">
<label class="ingredientLabel">{{ ingredientIndex + 1 }}.)</label>
<input class="ingredientInput" type="text" name="ingredients" v-model="ingredient.ingredient">
<button class="deleteIngredientButton" type="button" v-if="ingredientIndex > 0" @click="deleteIngredientForm(ingredientIndex)">X</button>
</div>
</div>
<div class="directionsContainer">
<label id="directionsLabel">Directions</label>
<button id="addDirectionButton" type="button" @click="addDirectionForm">Add Another Direction</button>
<div class="allDirections" v-for="(direction, directionIndex) in directions">
<label class="directionLabel">{{ directionIndex + 1 }}.)</label>
<input class="directionInput"type="text" name="directions" v-model="direction.direction">
<button class="deleteDirectionButton" type="button" v-if="directionIndex > 0" @click="deleteDirectionForm(directionIndex)">X</button>
</div>
</div>
<div id="createRecipeButtonContainer">
<button id="createRecipeButton" type="submit">Create Recipe</button>
</div>
</form>
</div>
<script src="/controls/newRecipeControl.js"></script>
</body>
</html>
再次感谢任何帮助。
解决方案
我知道有两种方法可以停止上传
- 您可以使用fileFilter。它是传递给 multer 的选项之一。但它只能用于检查文件类型等,因为
req.body
它可能只包含出现在表单中文件之前的字段。
const upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
// req.body is NOT reliable here
// it may only contain the some of the fields
// To reject this file pass `false`, like so:
cb(null, false)
// To accept the file pass `true`, like so:
cb(null, true)
// You can always pass an error if something goes wrong:
cb(new Error('I don\'t have a clue!'))
}
});
router.post('/createRecipe', ensureAuthenticated, upload.single('recipeImage'), function(req, res){
if(!req.file){
//the file was not uploaded
}
...
}
我也调查了你的回购。您fileFilter
作为选项传递给multer.diskStorage
. 这没有任何作用。multer.diskStorage
只接受 2 个选项destination
和filename
. 将其传递multer
给
- 使用 MemoryStorage(默认或替代),仅在满足条件时才保存到磁盘
推荐阅读
- amazon-web-services - 使用带有 EMR spark 的 terraform,在不破坏集群的情况下添加新步骤
- java - 用图像javafx填充文本?
- javascript - 我的页面加载后地理编码正在运行
- xamarin - Xamarin.forms - 滚动时“附加”StackLayout
- jdbc - kafka-connect-jdbc Teradata 接收器连接器错误
- docker - 如何从 CoreOS 上 docker 映像中的快照恢复 etcd 集群?
- isabelle - 显式实例化关于 Sequents 的公理
- c++ - 将矩阵(opencv)的向量转换为c ++数组
- python - 如何组合来自银行账户的两个数据框
- docker - 手动安装后我可以在 docker 中保存吗?