You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React前端通过Axios上传图片至Cloudinary并存MySQL时出错求助

问题描述

开发React Web应用时,表单支持文本输入和多图片上传,需求是将图片上传至Cloudinary,再把Cloudinary返回的图片URL和其他文本数据存入MySQL数据库。但目前图片无法传递到服务器,出现报错,需要修改图片输入的实现方式,求解决方案。

客户端代码
import { useState } from "react";
import Axios from 'axios';

function Verify() {
    // Text Inputs
    const [address, setAddress] = useState("")
    const [name, setName] = useState("")
    const [nic, setNIC] = useState("")
    // Image inputs
    const [nicfront, setNICFront] = useState("")
    const [nicback, setNICBack] = useState("")
    const [selfie, setSelfie] = useState("")

    const submitApplication = () => {
        console.log("start")
        Axios.post('http://localhost:3001/create', {
            address: address,
            name: name,
            nic: nic,
            nicfront: nicfront,
            nicback: nicback,
            selfie: selfie
        }).then(() => {
            console.log("Success")
        });
    };

    return (
        <>
            <section>
                <label>Address</label>
                <input type="text" onChange={(event) => { setAddress(event.target.value) }} />

                <label>Full Name</label>
                <input type="text" onChange={(event) => { setName(event.target.value) }} />

                <label>NIC Number</label>
                <input type="text" onChange={(event) => { setNIC(event.target.value) }} />


                <label>NIC Front</label>
                <input id="imagefront" name="imagefront" type="file" onChange={(event) => { setNICFront(event.target.value) }} />

                <label>NIC Back</label>
                <input id="imagefront" name="imagefront" type="file" onChange={(event) => { setNICBack(event.target.value) }} />

                <label>Upload a selfie with the NIC</label>
                <input id="imagefront" name="imagefront" type="file" onChange={(event) => { setSelfie(event.target.value) }} />

                <div>
                    <div class="control">
                        <button onClick={submitApplication} >Submit for Review</button>
                    </div>
                </div>
            </section>
        </>
    );
}
export default Verify;
服务端代码
const express = require("express");
const mysql = require("mysql");
const cors = require("cors");
const cloudinary = require("cloudinary").v2;
require('dotenv').config();

const cl_user = process.env.CLUSER;
const cl_key = process.env.CLKEY;
const cl_secret = process.env.CLSECRET;

const app = express()
app.use(cors());
app.use(express.json());

//  Cloudinary intergration
cloudinary.config({
    cloud_name: cl_user,
    api_key: cl_key,
    api_secret: cl_secret
});

const db = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '',
    database: 'blockverify'
})

app.post('/create', (req, res) => {
    var wallet = ""
    var name = ""
    var nic = ""
    var nicfront = ""
    var nicback = ""
    var selfie = ""
    var state = 1

    // Retrieving data from the client
    wallet = req.body.address
    name = req.body.name
    nic = req.body.nic

    nicfront = req.body.nicfront
    nicback = req.body.nicback
    selfie = req.body.selfie

    cloudinary.uploader.upload(nicfront.tempFilePath, function (err, result) {
        console.log("Error: ", err);
        console.log("Result: ", result);
        var frontURL = result.secure_url;

    });

    cloudinary.uploader.upload(nicback.tempFilePath, function (err, result) {
        console.log("Error: ", err);
        console.log("Result: ", result);
        var backURL = result.secure_url;

    });

    cloudinary.uploader.upload(selfie.tempFilePath, function (err, result) {
        console.log("Error: ", err);
        console.log("Result: ", result);
        var selfieURL = result.secure_url;

    });

    db.query("INSERT INTO applications (wallet, name, nic, nicfront, nicback, selfie, state) VALUE (?,?,?,?,?,?,?)", [wallet, name, nic, nicfurl, nicback, selfie, state], (err, result) => {
        if (err) {
            console.log(err)
        } else {
            res.send("Inserted!")
        }
    })
})

app.listen(3001, () => {
    db.connect(function (err) {
        if (err) throw err;
        console.log("Connected to MySQL!");
    });
});
报错信息
Error:  {
  message: 'Missing required parameter - file',
  name: 'Error',
  http_code: 400
}
Result:  undefined
/Users/sandaru/DATA DRIVE/Degree/L6/FYP/Project/block-verify/server/index.js:50
        var frontURL = result.secure_url;
                              ^

TypeError: Cannot read properties of undefined (reading 'secure_url')
    at /Users/sandaru/DATA DRIVE/Degree/L6/FYP/Project/block-verify/server/index.js:50:31
    at /Users/sandaru/DATA DRIVE/Degree/L6/FYP/Project/block-verify/server/node_modules/cloudinary/lib/utils/index.js:1259:14
    at IncomingMessage.<anonymous> (/Users/sandaru/DATA DRIVE/Degree/L6/FYP/Project/block-verify/server/node_modules/cloudinary/lib/uploader.js:507:9)
    at IncomingMessage.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
解决方案

核心问题分析

  1. 客户端用event.target.value获取的是文件路径字符串,不是实际的File对象,无法用于上传
  2. 直接用JSON格式提交文件,服务器无法解析,必须用FormData传递
  3. 服务端没配置文件解析中间件,无法接收上传的文件
  4. Cloudinary上传是异步操作,直接执行数据库插入会导致URL还未获取就插入,同时存在变量名错误(nicfurl未定义)

客户端修改

  1. 存储File对象而非路径:
// 初始化文件状态为null
const [nicfront, setNICFront] = useState(null)
const [nicback, setNICBack] = useState(null)
const [selfie, setSelfie] = useState(null)

// 修改文件输入的onChange事件
<label>NIC Front</label>
<input id="nicfront" name="nicfront" type="file" onChange={(e) => setNICFront(e.target.files[0])} />

<label>NIC Back</label>
<input id="nicback" name="nicback" type="file" onChange={(e) => setNICBack(e.target.files[0])} />

<label>Upload a selfie with the NIC</label>
<input id="selfie" name="selfie" type="file" onChange={(e) => setSelfie(e.target.files[0])} />
  1. 用FormData提交数据:
const submitApplication = () => {
    const formData = new FormData();
    formData.append('address', address);
    formData.append('name', name);
    formData.append('nic', nic);
    formData.append('nicfront', nicfront);
    formData.append('nicback', nicback);
    formData.append('selfie', selfie);

    Axios.post('http://localhost:3001/create', formData, {
        headers: { 'Content-Type': 'multipart/form-data' }
    }).then(() => console.log("Success"))
      .catch(err => console.error(err));
};

服务端修改

  1. 安装multer中间件:
npm install multer
  1. 配置multer并修改路由:
const multer = require('multer');
// 用内存存储文件,方便上传到Cloudinary
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

// 修改路由,添加multer处理多文件上传
app.post('/create', upload.fields([
    { name: 'nicfront', maxCount: 1 },
    { name: 'nicback', maxCount: 1 },
    { name: 'selfie', maxCount: 1 }
]), async (req, res) => {
    try {
        const { address, name, nic } = req.body;
        const state = 1;

        // 异步上传图片到Cloudinary,确保获取到URL后再操作数据库
        const frontRes = await cloudinary.uploader.upload(req.files.nicfront[0].path, { resource_type: 'auto' });
        const backRes = await cloudinary.uploader.upload(req.files.nicback[0].path, { resource_type: 'auto' });
        const selfieRes = await cloudinary.uploader.upload(req.files.selfie[0].path, { resource_type: 'auto' });

        // 插入数据库,传入正确的图片URL
        db.query(
            "INSERT INTO applications (wallet, name, nic, nicfront, nicback, selfie, state) VALUES (?,?,?,?,?,?,?)",
            [address, name, nic, frontRes.secure_url, backRes.secure_url, selfieRes.secure_url, state],
            (err, result) => {
                if (err) {
                    console.error(err);
                    return res.status(500).send("数据库插入失败");
                }
                res.send("提交成功!");
            }
        );
    } catch (err) {
        console.error(err);
        res.status(500).send("图片上传失败");
    }
});

额外注意事项

  • 确保Cloudinary的环境变量配置正确
  • 前端可添加验证逻辑,确保用户选择所有文件后再允许提交
  • 测试时需选择实际文件,避免空文件导致报错

内容的提问来源于stack exchange,提问作者Sandaru Fernando

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:51:30