首页 > 解决方案 > 使用 multer 进行图像上传时上传表单的问题。错误是Cast to string failed for value and internal server error

问题描述

Express、mongoDB、mongoose 和 multer。我有一个表格(注意:没有图片),我可以将其上传到我的数据库,并且快递服务器在上传时也能正常工作。

但是我有另一种带有图像的表格,所以我正在使用 multer。

上传时出现以下两个错误:

500内部服务器错误

模型“product”[0] { [0] product_image: { product_image: {} }, [0 ] sub_category: { sub_category: 'Sample', product_name: 'sample product' }, [0] product_name: { product_name: 'sample product', sub_category: 'Sample' }, [0] product_specs: [ { specification: 'Density' ,规范值:'500'}][0]}```

每个输入字段只有两个知道原型,我正在分享我在第 65 行的产品上传文件中使用的 console.log 的屏幕截图- 控制台日志

我正在分享我的以下代码 - 1 Mongoose Schema 文件 Product.js 2 React 表单 -Productupload 文件,3 路由文件(/产品),4 server.js,5 db.js

我想知道:是否由于原型与 Schema 和我的 req.body 不匹配而导致任何错误?我的 Multer 代码可以吗?,我还评论了 Grid-fs 代码,因为以前我使用过它,但是因为这给了我错误,所以我更改了我的代码。我应该切换回网格代码吗?是否还需要将图像上传到我的后端。

感谢您一直到现在,希望有人能帮助我,如果需要,准备分享代码沙盒。请帮助某人。

猫鼬模式

```

    const mongoose = require("mongoose");
    
    const ProductSchema = new mongoose.Schema({
      sub_category: {
        type: String,
        required: true,
      },
      product_image: {
        type: String,
        required: true,
      },
      product_name: {
        type: String,
        required: true,
      },
      product_specs: {
        type: [],
        required: true,
      },
    });
    module.exports = Product = mongoose.model("product", ProductSchema);

```

React Form 产品上传文件

```

    import React, { useState } from "react";
    import FormInput from "../Forminput/forminput";
    import CustomButton from "../Custombutton/custombutton";
    import axios from "axios";
    
    const ProductUpload = () => {
      const [sub_category, setSub_category] = useState({ sub_category: "" });
    
      const [product_name, setProduct_name] = useState({ product_name: "" });
    
      const [product_image, setProduct_image] = useState("");
    
      const [product_specs, setProduct_specs] = useState([
        {
          specification: "",
          specvalue: "",
        },
      ]);
      
      const imageSelectedHandler = (event) => {
        setProduct_image({ product_image: event.target.files[0] });
      };
    
      const handleChange1 = (e) => {
        const { name, value } = e.target;
    
        setSub_category({ ...sub_category, [name]: value });
        setProduct_name({ ...product_name, [name]: value });
      };
    
      const handleChange2 = (e, i) => {
        const { name, value } = e.target;
    
        const p_specs = [...product_specs];
        p_specs[i][name] = value;
        setProduct_specs(p_specs); //This is 100% right.
      };
    
      //to add extra input field
      const addClick = () => {
        const p_specs = [...product_specs];
        p_specs.push({ specification: "", specvalue: "" });
        setProduct_specs(p_specs);
      };
      //to remove extra input field
      const removeClick = (i) => {
        const p_specs = [...product_specs];
        p_specs.splice(i, 1);
        setProduct_specs(p_specs);
      };
      const handleSubmit = async (event) => {
        event.preventDefault();
        const newProduct = {
          product_image,
          sub_category,
          product_name,
          product_specs,
        };
        console.log(newProduct); //getting this in console.
        try {
          const config = {
            headers: {
              "Content-Type": "application/json",
            },
          };
          const body = JSON.stringify(newProduct);
    
          const res = await axios.post("/api/product", body, config);
          console.log(res.data);
        } catch (error) {
          console.error(error.response.data);
        }
      };
    
      const createUI = () => {
        return product_specs.map((item, i) => {
          return (
            <div key={i} className="inputgroup">
              <FormInput
                type="text"
                name="specification"
                handleChange={(e) => handleChange2(e, i)}
                value={item.specification}
                label="specification"
                required
                customwidth="300px"
              ></FormInput>
              <FormInput
                type="text"
                name="specvalue"
                handleChange={(e) => handleChange2(e, i)}
                value={item.specvalue}
                label="specification values seperated by quomas"
                required
              ></FormInput>
              <CustomButton
                onClick={() => removeClick(i)}
                type="button"
                value="remove"
                style={{ margin: "12px" }}
              >
                Remove
              </CustomButton>
            </div>
          );
        });
      };
      return (
        <div className="container">
          <form
            action="/product" //rout name
            method="post"
            className="form"
            onSubmit={handleSubmit}
            encType="multipart/form-data"
          >
            <h3 style={{ color: "roboto, sans-serif" }}>
              Add new product to the database
            </h3>
            <div
              style={{
                display: "flex",
                height: "200px",
                width: "200px",
                border: "2px solid #DADCE0",
                borderRadius: "6px",
                position: "relative",
              }}
            >
              <input
                // style={{ display: "none" }}
                type="file"
                accept="image/*"
                onChange={imageSelectedHandler}
                multiple={false}
                name="product_image"
              />
              <div>
                <img
                  style={{
                    width: "100%",
                    height: "100%",
                  }}
                  alt="#"
                />
              </div>
            </div>
            <FormInput
              type="text"
              name="sub_category"
              handleChange={handleChange1}
              value={sub_category.sub_category}
              label="select from subcategories"
              required
            ></FormInput>
    
            <FormInput
              type="text"
              name="product_name"
              handleChange={handleChange1}
              value={product_name.product_name}
              label="product name"
              required
            ></FormInput>
            {console.log(product_image)}
            {console.log(product_name)}
            {console.log(product_specs)}
            {createUI()}
            <div>
              <CustomButton
                onClick={addClick}
                type="button"
                style={{ margin: "14px" }}
              >
                Add More Fields
              </CustomButton>
              <CustomButton type="submit" style={{ margin: "12px" }}>
                Upload Product
              </CustomButton>
            </div>
          </form>
        </div>
      );
    };
    export default ProductUpload;

```

路线产品

```

    const express = require("express");
    const router = express.Router();
    const Product = require("../../models/Product");
    const { check, validationResult } = require("express-validator");
    //const GridFsStorage = require("multer-gridfs-storage");
    const multer = require("multer");
    const path = require("path");
    
    const Storage = multer.diskStorage({
      destination: "./client/public/uploads/",
      filename: (req, file, cb) => {
        cb(
          null,
          file.filename + "_" + Date.now() + path.extname(file.originalname)
        ); //fieldname will automatically get input filed name value in our case product_omage
      },
    });
    
    //middleware
    const upload = multer({ storage: Storage }).single("product_image");
    
    /*const storage = new GridFsStorage({
      db: connectDB(),
    });
    const upload = multer({ storage });
    module.exports = upload;*/
    
    // @route GET api/Product
    router.get("/", (req, res) => res.send("Product route"));
    
    // @route POST api/Product
    
    router.post(
      "/",
      [
        check("sub_category", "subcategory is required").not().isEmpty(),
        check("product_name", "product name is required").not().isEmpty(),
      ],
      upload,
      async (req, res) => {
        const errors = validationResult(req);
        console.log("req");
        if (!errors.isEmpty()) {
          return res.status(400).json({ errors: errors.array() });
        }
    
        const {
          sub_category,
          product_name,
          product_image,
          product_specs,
        } = req.body;
    
        console.log(req.body);
        console.log(req.body);
        try {
          //See if product exists
          let product = await Product.findOne({ product_name }); // Product.findOne() is mongo db query
    
          if (product) {
            return res
              .status(400)
              .json({ errors: [{ msg: "Product already exists" }] });
          }
    
          //New product instance will be created and once user.save() command is given user will be created in mongodb database.
          product = new Product({
            sub_category,
            product_name,
            product_image,
            product_specs,
          });
    
          await product.save();
        } catch (err) {
          console.error(err.message);
          res.status(500).send("Server error");
        }
      }
    );
    module.exports = router;

```

数据库文件

```

    const mongoose = require("mongoose");
    const config = require("config");
    const db = config.get("mongoURI");
    
    const connectDB = async () => {
      try {
        await mongoose.connect(db, {
          useUnifiedTopology: true,
          useNewUrlParser: true,
          useCreateIndex: true,
          useFindAndModify: false,
        });
    
        console.log("MongoDB connected...");
      } catch (err) {
        console.error(err.message);
        process.exit(1);
      }
    };
    
    module.exports = connectDB;

```

标签: reactjsmongodbexpressmongoosemulter

解决方案


推荐阅读