微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 Multer 在 MERN Stack 应用程序中上传图像文件

如何解决如何使用 Multer 在 MERN Stack 应用程序中上传图像文件

我正在尝试在我的项目中使用 multer 将图像作为文件上传,但我不知道为什么在控制台后端的 onCreate 请求我在 req.files: []; (空数组)。

这里是我创建一个元素的地方:

    const [imagesColors,setimagesColors] = useState([{image: [],color: ''}])
    
    const createProduct = (e) => {
        e.preventDefault ();
    
        const data = new FormData()
    
    data.append("name",name)
        data.append("description",description)
        data.append("processor",processor)
        data.append("ram",ram)
        data.append("storage",storage)
        data.append("imagesColors",imagesColors)
        data.append("price",price)
        data.append("type",type)
    
        console.log(data)
    
        fetch ('http://localhost:5000/products/create',{
          method: 'POST',body: data
        })...
    
    const handleInputChangeColor = (e,index) => {
        const { name,value } = e.target;
        const list = [...imagesColors];
        list[index][name] = value;
        setimagesColors(list);
      };
    
      const handleInputChangeImage = (e,index) => {
        const name = e.target.name;
        const file = e.target.files;
        const list = [...imagesColors];
        list[index][name] = file;
        setimagesColors(list);
      };
    
return (
...
    {imagesColors.map((x,i) => {
                        return (
                          <div className="Box">
                            <label htmlFor="file" className="file--Input--Container">
                              <input
                                type="file"
                                id="file"
                                multiple
                                name="image"
                                className="file--Input"
                                filename="imageFile"
                                placeholder="Product Image"
                                onChange={e => handleInputChangeImage(e,i)}
                              />
                              <div className="file--Label--Container">
                                 <FaCloudUploadAlt className="upload--Icon"/> Upload Images
                              </div>
                            </label>
                            <select
                              onChange={e => handleInputChangeColor(e,i)}
                              value={x.color}
                              name="color"
                              defaultValue=""
                            >
                              <option selected value="">Color</option>
                              <option value='#4f5b66'>Space-gray</option>
                              <option value='#a7adba'>Silver</option>
                              <option value='#FFFFFF'>White</option>
                              <option value='#F63204'>Red</option>
                              <option value='#000000'>Black</option>
                              <option value='#0095CB'>Pacific-Blue</option>
                            </select>
                            <div className="btn-Box">
                              {imagesColors.length !== 1 && <button onClick={() => handleRemoveClick(i)}>Remove</button>}
                              {imagesColors.length - 1 === i && <button onClick={handleAddClick}>Add</button>}
                            </div>
                          </div>
                        );
                      })}

当我 console.log 状态 imagesColors 它返回:

enter image description here

这是后端带有multer函数的create函数

const imageStorage = multer.diskStorage({
    destination: (req,file,callback) => {
        callback(null,"../../shpJS/frontend/src/styles/images")
    },filename: (req,file.name)
    }
})

const uploads = multer({storage: imageStorage})

router.post('/create',uploads.array("imagesColors"),async (req,res) => {
    console.log(req,' asd')
    try {
        const data = {
            name: req.body.name,description: req.body.description,processor: req.body.processor,ram: req.body.ram,storage: req.body.storage,imagesColors: req.files,price: req.body.price,type: req.body.type,likes: req.body.likes
        }
        let product = await productService.create(data)
        res.status(201).json(product)
    } catch (error) {
        res.status(500).json({error: error})
    }
})

来自请求的控制台结果:

enter image description here

解决方法

您将 imageColors 作为对象数组(不是文件数组)发送,其中包括图像文件列表和颜色。您还需要在表单数据键的末尾添加括号,否则将无法正确解析。

您可以在发送前映射 imageColors 对象:

data.append("imagesColors[]",imagesColors.map(i) => i.images[0])

如果你也想发送颜色名称,你必须将它们发送到另一个数组中:

data.append("colors[]",imagesColors.map(i) => i.color)
,

要使用 FormData API 在前端发送多个文件,您必须将这些文件一一附加。您可以将它们附加到同一个字段,该字段将作为一个数组到达后端。如果您想与每个文件一起发送额外的数据,请以相同的顺序将该数据附加到不同的字段。

在你的情况下,它看起来像这样:

for (const imageAndColor of imagesColors) {
  data.append('images',imageAndColor.image);
  data.append('colors',imageAndColor.color);
}

并在后端将 uploads.array("imagesColors") 更改为 uploads.array("images")。您的图像将采用 req.files,颜色采用 req.body.colors。两个数组的顺序是有保证的——第一个图像是两个数组中的第一个元素,第二个图像是第二个元素,依此类推。

,

作为提出这个问题的人接受任何解决问题的方法(见这个问题的评论)。我正在使用一种不使用任何包(如 multer)来上传文件的方法进行回答。

所以该方法是先在前端将图像转换为base64,然后将其发送到后端,然后在后端将base 64转换回文件。

以下是将文件转换为 base64 的前端代码。

传递的参数images不过是event.target.files

const [imagesArray,setImagesArray]=useState()

let imageToBase64=(images)=>{  //passed parameter images here
    let imagesBase64=[]
    for(let image of images){
      const reader = new FileReader();

    reader.onload = () => {
      if (reader.readyState === 2) {
        let imageBase64=reader.result
        imagesBase64.push(imageBase64)
      }
    };
    reader.readAsDataURL(image);
  }
  setImagesArray(imagesBase64);
  }

设置前端以如下格式发送数据

{
    name: req.body.name,description: req.body.description,processor: req.body.processor,ram: req.body.ram,storage: req.body.storage,imagesColors: [base64 string,base64 string],//differnce here
    price: req.body.price,type: req.body.type,likes: req.body.likes
}

后台代码

将 base64 转换为文件(我相信您正在上传图像,所以我使用了sharp包)

将此行放在根文件中(可能是 index.js 或 app.js) app.use(express.json({limit: '50mb'}))

const sharp = require("sharp");
const FileType = require("file-type");


router.post('/create',async (req,res) => {
    
 async function convert(base64) {
  var buffer = Buffer.from(base64.split(";base64,").pop(),"base64");
  let {ext} = await FileType.fromBuffer(buffer);
  let newPath =
    `/public/any path/` +
    Date.now() +
    Math.random().toString().slice(2,14) +
    "." +
    ext;

  await sharp(buffer)
    .resize(1920,1080)
    .toFile(newPath)
    .catch(err => console.log(err));

   return "done"
};

//this converts all base64 to images.
//warning: never `console.log(req.body.imagesColors)` because base64 is very very long string and logging that can crash your terminal.

if (req.body.imagesColors.length > 0)
    for (let image of req.body.imagesColors)
      await convert(image)
})

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。