NodeJS 如何使用Formidable和React Js将多个图像文件上传到服务器

8mmmxcuj  于 2022-12-18  发布在  Node.js
关注(0)|答案(2)|浏览(120)

我试图上传五个图像到服务器,但我无法做到这一点。我的代码文件如下,任何人的帮助将不胜感激。
在这里,我获取图像文件输入并将其存储到一个图像数组中,但是当向后端发出post请求时,Formidable将图像视为表单字段对象,而不是文件。
我理解这个问题,但无法找到解决这个问题的方法。
前端代码

const Addproducts = () => {

    const { user, token } = isAuthenticated() ? isAuthenticated() : { user: "", token: "" };

    const [imgUrl, setImgUrl] = useState({
        imageFirst: "",
        imageSecond: "",
        imageThird: "",
        imageFourth: "",
        imageFifth: ""
    });

    const { imageFirst, imageSecond, imageThird, imageFourth, imageFifth } = imgUrl;

    const [product, setProduct] = useState({
        name: "",
        code: "",
        stock: "",
        price: "",
        category: "",
        categories: [],
        description: "",
        images: "",
        formData: "",
        error: ""
    });

    const { name, code, stock, price, category, categories, description, images, formData } = product;

    useEffect(() => {
        getAllCategories()
            .then((data) => {
                if (data.error) {
                    setProduct({ ...product, error: data.error });
                } else {
                    setProduct({ ...product, categories: data, formData: new FormData() });
                }
            })
            .catch(err => console.log(err));
    }, []);

    const onImageChange = name => event => {

        if (event.target.files[0]) {
            var reader = new FileReader();

            reader.readAsDataURL(event.target.files[0]);

            reader.onload = (e) => {
                setImgUrl({ ...imgUrl, [name]: e.target.result });
            }

            images.push(event.target.files[0]);

            console.log(images);
        }
    };

    const handleChange = (name) => event => {

        const value = name === "description" ? event : event.target.value;

        formData.set(name, value);

        setProduct({ ...product, [name]: value });

    };

    const onPost = (event) => {
        event.preventDefault();

        formData.set("images", images);

        createProduct(formData, user._id, token)
            .then(data => {
                if (data.error) {
                    console.log(data.error);
                } else {
                    console.log(data);
                }
            })
            .catch(err => console.log(err));

    };

    const onDiscard = (event) => {
        event.preventDefault();

        setProduct({
            ...product,
            name: "",
            code: "",
            stock: "",
            price: "",
            category: "",
            description: "",
            images: []
        });

        setImgUrl({ ...imgUrl, imageFirst: "", imageSecond: "", imageThird: "", imageFourth: "", imageFifth: "" });
    };

    return (
        <Layout pageHeaderTitle={"Add Product"} >
            <div className="add-product-page">
                <div className="page-body">
                    <form className="input-form">
                        <div className="row">
                            <div className="col-12 product-images">
                                <div className="image-input-div">
                                    <label>Product Images:</label>
                                    <ul className="image-input-list">
                                        <li>
                                            <div className="image-input">
                                                <input onChange={onImageChange("imageFirst")} type="file" />
                                                <i className="bi bi-image" />
                                                {imageFirst && <img src={imageFirst} alt="product img" />}
                                            </div>
                                        </li>
                                        <li>
                                            <div className="image-input">
                                                <input onChange={onImageChange("imageSecond")} type="file" />
                                                <i className="bi bi-image" />
                                                {imageSecond && <img src={imageSecond} alt="product img" />}
                                            </div>
                                        </li>
                                        <li>
                                            <div className="image-input">
                                                <input onChange={onImageChange("imageThird")} type="file" />
                                                <i className="bi bi-image" />
                                                {imageThird && <img src={imageThird} alt="product img" />}
                                            </div>
                                        </li>
                                        <li>
                                            <div className="image-input">
                                                <input onChange={onImageChange("imageFourth")} type="file" />
                                                <i className="bi bi-image" />
                                                {imageFourth && <img src={imageFourth} alt="product img" />}
                                            </div>
                                        </li>
                                        <li>
                                            <div className="image-input">
                                                <input onChange={onImageChange("imageFifth")} type="file" />
                                                <i className="bi bi-image" />
                                                {imageFifth && <img src={imageFifth} alt="product img" />}
                                            </div>
                                        </li>
                                    </ul>
                                </div>
                            </div>
                            <div className="col-12 product-details">
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Product Name :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <input onChange={handleChange("name")} value={name} type="text" />
                                    </div>
                                </div>
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Product Code :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <input onChange={handleChange("code")} value={code} type="text" />
                                    </div>
                                </div>
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Stock :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <input onChange={handleChange("stock")} value={stock} type="number" />
                                    </div>
                                </div>
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Price :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <input onChange={handleChange("price")} value={price} type="number" />
                                    </div>
                                </div>
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Category :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <select onChange={handleChange("category")} value={category}>
                                            <option>Select</option>
                                            {categories.map((cate, index) => {
                                                return <option key={index} value={cate._id}>{cate.name}</option>
                                            })}
                                        </select>
                                    </div>
                                </div>
                                <div className="product-details-group row">
                                    <label className="col-xl-3 col-sm-4">Description :</label>
                                    <div className="col-xl-8 col-sm-8 input-div">
                                        <Editor
                                            apiKey="o00fsajpo4j9r64yyjk33l33939uwqsavka5jlyhnhcwp5kn"
                                            init={{
                                                height: 500,
                                                menubar: true,
                                                plugins: [
                                                    'advlist autolink lists link image charmap print preview anchor',
                                                    'searchreplace visualblocks code fullscreen',
                                                    'insertdatetime media table paste code help wordcount'
                                                ],
                                                toolbar:
                                                    'undo redo | formatselect | bold italic backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help'
                                            }}
                                            outputFormat='html'
                                            value={description}
                                            onEditorChange={handleChange("description")}
                                        />
                                    </div>
                                </div>
                            </div>
                            <div className="col-12 submit-btn-group">
                                <button onClick={onPost} className="post-btn">Post</button>
                                <button onClick={onDiscard} className="discard-btn">Discard</button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </Layout>
    );
};

export default Addproducts;

后端代码

exports.createProduct = (req, res) => {
    //get the form data using formidable
    let form = new formidable.IncomingForm();
    form.keepExtensions = true;

    //parse the form data
    form.parse(req, (err, fields, file) => {
        if (err) {
            return res.status(400).json({ error: "Problem with image" });
        }
        //destructure the fields' data if there is no error  
        const { name, description, price, category, stock } = fields;
        //validate the data
        //if (!name || !code || !description || !price || !category || !stock) {
         //   return res.status(400).json({ error: "Please include all the fields" });
        //}

        // create document 
        //let product = new Product(fields);

        // handle the file
        //if (file.photo) {
            //file size should not be more than 3MB
         //   if (file.photo.size > 3 * 1024 * 1024) {
               // return res.status(400).json({ error: "File size is too big" });
         //   }
         //   product.photo.data = fs.readFileSync(file.photo.path);
         //   product.photo.contentType = file.photo.type;
       //}

        //save product in database
       // product.save((err, product) => {
         //   if (err) {
           //     return res.status(400).json({ error: "There was an error creating a product" });
         //   }
         //   return res.json(product);
        //});
        
        console.log(file, fields);
    });
};
nimxete2

nimxete21#

我建议使用Multer来上传images/videos/files
以下是 Package :https://www.npmjs.com/package/multer
后端代码类似于:
您可以创建一个文件image-upload.js并添加以下代码:

const multer = require('multer');

const imageStorage = multer.diskStorage({
  destination: (req, file, callback) => {
    callback(null, `${process.env.SERVER_STORAGE}/images`);
  },
  filename: (req, file, callback) => {
    callback(null, `image_${Date.now()}`)
  }
});

const imageFilter = (req, file, callback) => {
  if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/jfif' || file.mimetype === 'image/jpg' || file.mimetype === 'image/png' || file.mimetype === 'image/gif') {
    callback(null, true)
  } else {
    callback(new Error('Image type not supported!'), false);
  }
}

const image_upload = multer({ storage: imageStorage, fileFilter: imageFilter });

module.exports = { image_upload };

现在在你的router中你可以从image-upload.jsimport这个imageUpload

const express = require('express');
const imageUpload = require('./image-upload');

const router = express.Router();

router.post('/image-upload', imageUpload.array('images'), (req, res, next) => {

   console.log(req.files)
   // If this code is executed that means that images are uploaded successfully and you can access them in 'req.files'

});
mpgws1up

mpgws1up2#

设置选项以接受multiple文件

const form = new formidable.IncomingForm({ multiples: true })

相关问题