我正在开发一个应用程序,它使用 multer 中间件一次将多个文件存储到数据库中。我已完成所有设置并正常工作,但每隔几次尝试,我的上传就会失败,并且没有错误消息。它会上传文件,但不会保存到数据库,也不会生成错误消息。
下面是前端代码(表单和附带函数)
import React, { useState } from 'react'
import BackButton from '../components/BackButton';
import Spinner from '../components/Spinner';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
export const CreatePhoto = () => {
const [category, setCategory] = useState({});
const newFiles = [];
const [files, setFiles] = useState({});
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const handleChange = (e) => {
setCategory(e.target.value);
console.log(e.target.value);
}
const handlePhoto = (e) => {
setFiles(e.target.files)
}
const handleSubmit = () => {
console.log(files);
const formData = new FormData();
formData.append('category', category);
for (let i=0; i<files.length;i++){
formData.append('photo', files[i]);
}
console.log(...formData);
alert('Working for now, lets see how it goes!');
setLoading(true);
axios
.post('http://localhost:5555/uploadImage', formData)
.then(() => {
alert("Checking ...");
setLoading(false);
navigate('/');
})
.catch((error) => {
setLoading(false);
alert('An error occured. Please check console!!');
console.log(error);
});
};
return (
<div className='p-4'>
<BackButton />
<h1 className='text-3xl my-4'>Upload Photos</h1>
{loading ? <Spinner /> : ''}
<div className='flex flex-col border-2 border-sky-400 rounded-xl w-[600px] p-4 mx-auto'>
<form onSubmit={handleSubmit} encType='multipart/form-data'>
<div className='my-4'>
<label className='mb-2 inline-block text-neutral-500 dark:text-gray-800' htmlFor='category'>Category</label>
<select id="category" name="category"
className='bg-gray-50 border-2 border-yellow-600 text-gray-900 text-base rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-100 dark:border-yellow-500 dark:placeholder-gray-400 dark:text-gray-800 dark:focus:ring-blue-500 dark:focus:border-blue-500'
onChange={handleChange}>
<option defaultValue={'Reception'}>Choose a Category</option>
<option value="Traditional">Traditional</option>
<option value="Court">Court</option>
<option value="Reception">Reception</option>
</select>
</div>
<div className='mb-3'>
<label
htmlFor="formFileMultiple"
className='mb-2 inline-block text-neutral-500 dark:text-gray-800'
>Upload Images</label>
<input
className='relative m-0 block w-full min-w-0 flex-auto cursor-pointer rounded border border-2 border-yellow-500 bg-gray-100 bg-clip-padding px-3 py-[0.32rem] text-base font-normal text-surface transition duration-300 ease-in-out file:-mx-3 file:-my-[0.32rem] file:me-3 file:cursor-pointer file:overflow-hidden file:rounded-none file:border-0 file:border-e file:border-solid file:border-inherit file:bg-transparent file:px-3 file:py-[0.32rem] file:text-surface focus:border-primary focus:text-gray-700 focus:shadow-inset focus:outline-none dark:border-yellow dark:text-black file:dark:text-black'
type="file"
name="photo"
onChange={handlePhoto}
id="formFileMultiple"
multiple="multiple" />
</div>
<button className='p-2 bg-sky-300 m-8' type='submit'>
Upload
</button>
</form>
</div>
</div>
)
}
export default CreatePhoto
这是后端代码
.
.
.
const fileStorage = multer.diskStorage({
destination: 'images',
filename : (request, file, cb) => {
cb(null, file.fieldname + '_' + Date.now() + path.extname(file.originalname));
}
});
const uploadImage = multer({
storage : fileStorage,
limits : {
fileSize: 10000000
},
fileFilter(request, file, cb) {
if (!file.originalname.match(/\.(png|jpg|jpeg)$/)) {
return cb(new Error('Please upload an Image file!'));
}
cb(undefined, true);
}
});
app.post('/uploadImage', uploadImage.array('photo', 20), async (request, response) => {
const files = request.files;
console.log(request.body);
console.log(request.files);
const imgArray = await files.map((file) => {
const img = fs.readFileSync(file.path);
return img.toString('base64');
});
imgArray.map(async (src, index) => {
const finalImg = {
title : files[index].originalname,
path : files[index].path,
fileSize : files[index].size,
category : request.body.category
}
console.log();
const newUpload = new Photo(finalImg);
try {
await newUpload.save();
console.log("Upload was good");
response.json('Upload was successful!!');
} catch (error) {
response.status(400).json({error:error.message || `Something went wrong somewhere`});
}
});
});
我尝试将 post 请求设为异步,因为我的想法是由于数据库连接问题而遇到了延迟;也许连接速度慢或类似的东西。所以我认为使用异步可以解决问题,但我不太确定我是否有效地使用了它,或者在这种情况下它是否没有帮助。
我期望的功能是所有上传命令都成功,或者如果有原因导致上传无法正常工作,我会生成一条特定的错误消息。
将await与async一起使用不会产生任何效果,因为
await
将阻塞异步函数并等待作业完成(直到promise解析)。
同样在您的情况下,使用
.map
函数是错误的,它用于创建新数组。您可以使用 .forEach
来代替。
无论哪种方式,在循环中,一旦第一个项目被处理,它都会向客户端发送响应,这将中断服务器请求并停止进程。
所以我建议使用 Promise 并行处理所有图像。
app.post('/uploadImage', uploadImage.array('photo', 20), async (request, response) => {
try {
const files = request.files;
const promises = files.map((file) => {
return new Promise(async (resolve) => {
// const img = fs.readFileSync(file.path);
// const imgBase64 = img.toString('base64');
const finalImg = {
title: file.originalname,
path: file.path,
fileSize: file.size,
category: request.body.category
};
const newUpload = new Photo(finalImg);
await newUpload.save();
resolve('Upload was good');
});
});
await Promise.all(promises);
response.json('Upload was successful!!');
} catch (error) {
response.status(500).json({ error: error });
}
});
希望这有帮助!