如何将图像上传到 Cloudinary - MERN 堆栈

Posted

技术标签:

【中文标题】如何将图像上传到 Cloudinary - MERN 堆栈【英文标题】:How to upload Image to Cloudinary - MERN Stack 【发布时间】:2021-10-10 16:21:12 【问题描述】:

我想向 mongo DB 添加一些公司详细信息,详细信息包括公司徽标。所以我想将图片上传到 Cloudinary,然后将 URL 与其他详细信息一起保存在 Mongo DB 中。

但我的代码似乎不起作用。当我填写表格并点击提交时,图像会上传到 Cloudinary,但不会保存在数据库中。

存储图像

const [ companyLogo, setCompanyLogo] = useState("");
const [ companyLogoURL, setCompanyLogoURL] = useState("");

提交时执行的函数

const handleCompanySubmit = (evt) => 
    evt.preventDefault();

    const data = new FormData()
    data.append("file", companyLogo)
    data.append("upload_preset", "Sprint")
    data.append("cloud_name", "sprint-ccp")
    fetch("https://api.cloudinary.com/v1_1/sprint-ccp/image/upload",
      method:"post",
      body:data
    )
    .then(res => res.json())
    .then(data => 
      setCompanyLogoURL(data.url)
    )
    .catch(err => 
      console.log(err)
    )

    //check for empty fields
    if (
      isEmpty(companyName) ||
      isEmpty(companyAddress) ||
      isEmpty(companyRegNumber) ||
      isEmpty(companyContactNumber)
    ) 
      setCompanyErrorMsg("Please Fill All The Fields");
    else 
      let formData = new FormData();
      formData.append('companyName', companyName);
      formData.append('companyAddress', companyAddress);
      formData.append('companyRegNumber', companyRegNumber);
      formData.append('companyContactNumber', companyContactNumber);
      formData.append('companyLogo', companyLogoURL);

      setCompanyLoading(true);

      addCompany(formData)
      .then((response) => 
        setCompanyLoading(false);
          setCompanySuccessMsg(response.data.successMsg)
          setCompanyData(
            companyName: "",
            companyAddress: "",
            companyRegNumber: "",
            companyContactNumber: ""
          );
      )
      .catch((err) => 
        setCompanyLoading(false);
        setCompanyErrorMsg(err.response.data.errorMsg)
      )
    
  ;

const handleCompanyLogo = (evt) => 
    setCompanyLogo(evt.target.files[0])
  ;

前端视图

<form className="register-form" onSubmit=handleCompanySubmit noValidate>

     <label className="text-secondary">Company Logo :</label>
     <input type="file"  className="form-control" onChange=handleCompanyLogo/>

     //remaining input fields

     <button className="btn btn-info submitButton" >Submit</button>
                  
</form>
    
    

添加公司的api

export const addCompany = async (data) => 
    const config = 
      headers: 
        "Content-Type": "application/json",
      ,
    ;
  
    const response = await axios.post(
      "http://localhost:5000/api/auth/clients/company",
      data,
      config
    );
  
    return response;
  ;

后台控制器

exports.addNewCompany = async(req,res)=>

  const  
    companyName,
    companyAddress,
    companyRegNumber,
    companyContactNumber,
    companyLogo
   = req.body;

  const company = await Company.findOne( companyName );
    if (company) 
      return res.status(400).json(
        errorMsg: `$req.body.companyName already exists`,
      );
    

  try
    const newCompany = new Company();
    newCompany.companyName = companyName;
    newCompany.companyAddress = companyAddress;
    newCompany.companyRegNumber = companyRegNumber;
    newCompany.companyContactNumber = companyContactNumber;
    newCompany.companyLogo = companyLogo;

    await newCompany.save();
    res.json(
      successMsg: `$req.body.companyName Company Added Successfully`
    );
   catch (err) 
    console.log("clientsController error - Add Company ", err);
    res.status(500).json(
      errorMsg: "Server Error. Please Try again",
    );
  
;

我在控制台中遇到的错误是这样的

clientsController 错误 - 添加公司错误:公司验证失败:companyLogo:需要路径 companyLogo 在 ValidationError.inspect 处

(C:\CCP\sd08_2021\Backend\node_modules\mongoose\lib\error\validation.js:47:26)

你能帮帮我吗?

【问题讨论】:

您需要先将图像上传到您的服务器,然后将其从您的服务器发送到云服务器。使用multer 包将文件上传到您的服务器,然后使用cloudinary 包将其发送到云服务。这两个包都可以从 NPM 获得。 不发送到服务器就没有办法了吗? 没有。如果不注册 cloudinary 帐户并获取该帐户的 API 密钥,则无法将图像上传到 cloudinary。您不想在浏览器中使用这些 API 密钥,因为您的网站用户可以窃取您的 API 密钥,并对您的云帐户做任何他们想做的事情(例如删除任何图像,或上传淫秽图像)。出于这个原因,您需要在服务器端做所有事情。您的用户会将图像发送到您的服务器,然后您的服务器会将其发送到 cloudinary,然后 cloudinary 将返回带有图像 url 的响应,然后您可以更新数据库.. @TJBlackman 关于在客户端公开 API 机密的说法是正确的。但是,您可以使用未签名上传或签名上传上传到 Cloudinary,而不会暴露您的 API 机密。后者是首选,因为它更安全。 【参考方案1】:

我认为您的错误是由一个更琐碎的问题引起的:

当您使用 fetch 发送 POST 请求时,您实际上并没有等待它的完成(这是一个承诺),因此if ... else ... 语句中的代码在 fetch() 终止之前执行 /em> !

setCompanyLogoURL(data.url) 尚未被调用,因此formData.append('companyLogo', companyLogoURL); 设置一个空白字符串,而不是调用 Cloudinary API 返回的值。

解决方案是使handleCompanySubmit 异步,并等待fetch() 承诺完成。

【讨论】:

以上是关于如何将图像上传到 Cloudinary - MERN 堆栈的主要内容,如果未能解决你的问题,请参考以下文章

如何将缓冲区图像上传到 cloudinary?

如何将图像从 android 上传到 Cloudinary?

Nuxt.js - 如何将图像上传到 cloudinary?

如何使用流明通过android将图像文件上传到cloudinary

如何使用自定义 url 和文件夹将图像上传到 cloudinary

如何在节点中使用 multer 将图像上传到 cloudinary 并与其他数据一起表达