反应节点通过 axios 传递文件与 multer 错误 500

Posted

技术标签:

【中文标题】反应节点通过 axios 传递文件与 multer 错误 500【英文标题】:react node passing file through axios with multer error 500 【发布时间】:2020-10-20 15:05:10 【问题描述】:

我正在尝试制作简单的表单来将文件和其他一些数据传递到我的服务器。稍后我会尝试添加数据库查询,但现在我看不到那里有任何数据传输,所以我卡住了。

我使用 react 创建了前端:

const [mainPicture, setMainPicture] = useState(null);
const [pictures, setPictures] = useState([]);
const [name, setName] = useState('Name');
const config = 
    headers: 
        'content-type': 'multipart/form-data'
    
;

function handleSubmit(e) 
    e.preventDefault();

    const formData = new FormData();
    formData.append('name', name);
    formData.append('mainPicture', mainPicture);

    console.log(formData);

    axios
        .post(
            prefix + '/api/add_project',
            formData, 
            headers: config.headers,
            onUploadProgress: progressEvent => 
                console.log('Upload Progress: ' + Math.round(progressEvent.loaded / progressEvent.total * 100) + '%');
            
        )
        .then((response) => 
            alert(response);
        )
        .catch((error) => 
            console.log(error);
        );


const onDrop = (picture) => 
    setPictures([...pictures, picture]);
;

return (
    <div>
        <form encType="multipart/form-data" onSubmit=handleSubmit>
            <label>
                Name:
                <input value=name onChange=(e)=> setName(e.target.value)
                type="text"/>
            </label>
            <label>
                Project Description:
                <input onChange=(e)=> setDescription(e.target.value)
                value=description
                type="text"
                />
            </label>
            <label>
                Project Address:
                <input onChange=(e)=> setAddress(e.target.value)
                value=address
                type="text"
                />
            </label>
            <label>
                Used Products:
                <input onChange=(e)=> setUsed(e.target.value)
                value=used
                type="text"
                />
            </label>
            <label>
                About Products:
                <input onChange=(e)=> setAbout(e.target.value)
                value=about
                type="text"
                />
            </label>
            <input type="file" name="mainPicture" onChange=e=> setMainPicture(e.target.files[0]) />
            <button type="submit">Upload</button>
        </form>
    </div>
);

然后我在路由中使用 node express 创建了后端函数 从前端获取 api 调用,遵循教程,但我无法在这里找出问题。

var multer = require('multer')
const DIR = './public/images/projects';

const storage = multer.diskStorage(
    destination: (req, file, cb) => 
        cb(null, DIR);
    ,
    filename: (req, file, cb) => 
        const fileName = file.originalname.toLowerCase().split(' ').join('-');
        cb(null, fileName)
    
);

const upload = multer( storage );

//ADD NEW PROJECT
router.post('/api/add_project', upload.single('mainPicture'), (req, res, next) => 
    console.log("Body ---", req.body);
    console.log('Files--', req.file);
    console.log('file name: ', req.file.name);
);

在我的 pm2 监控中,我得到了这个:

有什么问题?

【问题讨论】:

问题是你需要处理multipart/form-data。用于将请求中的数据解析为request.body(通常为bodyparser 或express.json)的中间件不适用于此类数据。可用于解析多部分表单数据的替代中间件是 multer。 @jme11 用 multer 制作,同样的问题,按照本教程编辑了我的问题:blog.stvmlbrn.com/2017/12/17/… 能否请您修复第一个代码 sn-p 因为它包含语法错误? (见最后一行) @macborowy 看不到任何语法错误 【参考方案1】:

似乎有一个issue 带有标头content-type,他们说不应传递标头,因此axios 可以将其设置为适当的边界。

希望这会有所帮助。

【讨论】:

那么我应该如何编辑我的配置?我不明白。 仅删除 headers: config.headers, 行就足够了 @Emilis 。希望这会有所帮助。【参考方案2】:

由于您在 html 表单中定义了 enctype,因此在标题中不需要它。这是修改后的代码

const [mainPicture, setMainPicture] = useState(null);
const [pictures, setPictures] = useState([]);
const [name, setName] = useState('Name');
const config = 
    headers: 
        'content-type': 'multipart/form-data'
    
;

function handleSubmit(e) 
    e.preventDefault();

    const formData = new FormData();
    formData.append('name', name);
    formData.append('mainPicture', mainPicture);

    console.log(formData);

    axios
        .post(
            prefix + '/api/add_project',
            formData, 
            onUploadProgress: progressEvent => 
                console.log('Upload Progress: ' + Math.round(progressEvent.loaded / progressEvent.total * 100) + '%');
            
        )
        .then((response) => 
            alert(response);
        )
        .catch((error) => 
            console.log(error);
        );


const onDrop = (picture) => 
    setPictures([...pictures, picture]);
;

return (
    <div>
        <form encType="multipart/form-data" onSubmit=handleSubmit>
            <label>
                Name:
                <input value=name onChange=(e)=> setName(e.target.value)
                type="text"/>
            </label>
            <label>
                Project Description:
                <input onChange=(e)=> setDescription(e.target.value)
                value=description
                type="text"
                />
            </label>
            <label>
                Project Address:
                <input onChange=(e)=> setAddress(e.target.value)
                value=address
                type="text"
                />
            </label>
            <label>
                Used Products:
                <input onChange=(e)=> setUsed(e.target.value)
                value=used
                type="text"
                />
            </label>
            <label>
                About Products:
                <input onChange=(e)=> setAbout(e.target.value)
                value=about
                type="text"
                />
            </label>
            <input type="file" name="mainPicture" onChange=e=> setMainPicture(e.target.files[0]) />
            <button type="submit">Upload</button>
        </form>
    </div>
);

经过一些修改的服务器端代码

var express = require('express');
var app = express();
var multer = require('multer')
var cors = require('cors');
app.use(cors())

var storage = multer.diskStorage(
      destination: function (req, file, cb) 
      cb(null, 'public')
    ,
    filename: function (req, file, cb) 
      cb(null, Date.now() + '-' +file.originalname )
    
)
var upload = multer( storage: storage ).single('mainPicture')
app.post('/api/add_project',function(req, res,next) 
     
    upload(req, res, function (err) 
           if (err instanceof multer.MulterError) 
               return res.status(500).json(err)
            else if (err) 
               return res.status(500).json(err)
           
      return res.status(200).send(req.file)

    )

);

如果您仍有问题,请关注此step by step guide.

【讨论】:

可以,不工作,但也许我做错了什么。我的 post 方法在 routes/users.js 我已经在 app.js 主文件中包含了 cors。我还需要将它包含在我的 post 方法所在的 users.js 中吗? 那我不知道还能做什么。没有什么能解决这个问题。【参考方案3】:

我猜Content-Type 标头区分大小写。 "Content-Type": "multipart/form-data"

这对我有用

【讨论】:

以上是关于反应节点通过 axios 传递文件与 multer 错误 500的主要内容,如果未能解决你的问题,请参考以下文章

multer req.files undefined with axios in react

反应,节点 axios 不工作,但 fetch 工作

Express multer 在 req.file 上返回 undefined

如何通过 Axios 将复杂对象从反应发布到节点?

如何修复 Axios 中的图片上传问题

如何将值从反应本机应用程序传递到节点 js 后端