首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Multer和Formik上传图像到Mongodb (MERN)

用Multer和Formik上传图像到Mongodb (MERN)
EN

Stack Overflow用户
提问于 2021-04-28 18:09:09
回答 3查看 706关注 0票数 0

我用MERN创建了应用程序。现在我正试图用Multer和Formik上传图片,但是req.file返回undefined,我不明白为什么。我是这方面的新手,但我想这可能是JSON.stringify (http.hook)或content-type: application/json造成的。我也尝试过用FormData来做这个,但这是行不通的。有什么想法吗?

更新:与邮递员工作良好。我认为问题是在ui部分,输入不传递文件。

app.js

代码语言:javascript
复制
const {Router} = require('express');
const multer = require('multer');
const auth = require('../middleware/auth.middleware');
const Users= require('../models/Users');
const router = Router();

const storage = multer.diskStorage({
   destination: function (req, file, cb) {
        cb(null, './client/public/uploads/');
   },
    filename: function (req, file, cb) {
        cb(null, file.originalname);
    },
});

const upload = multer({
    storage: storage,
    limits: { fileSize: 10 * 1024 * 1024 }
});


router.post('/create', upload.single('image'), auth, async (req, res) => {
    console.log(req.file);

    try {
        const code = req.body.code;

        const existing = await Users.findOne({code: code});

        if(existing) {
            return res.json({user: existing})
        }

        const user = new Users(req.body);

        await user .save();

        res.status(201).json(user);
    } catch (e) {
        console.log(e);
        res.status(500).json({ message: 'Error: try again.' })
    }
});

http.hook.js

代码语言:javascript
复制
import {useState, useCallback} from 'react';

export const useHttp = () => {
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);

    const request = useCallback(async (url, method = 'GET', body = null, headers = {}) => {
        setLoading(true);

        try {
            if(body) {
                body = JSON.stringify(body);
                headers['Content-Type'] = 'application/json';
            }

            const response = await fetch(url, {method, body, headers});
            const data = await response.json();

            if(!response.ok) {
                throw new Error(data.message || 'Something goes wrong')
            }

            setTimeout(() => {
                setLoading(false);
            }, 800);

            return data
        } catch (e) {
            setLoading(false);
            setError(e.message);

            throw e;
        }
    }, []);

    const clearError = useCallback(() => {setError(null)}, []);

    return {loading, request, error, clearError}};

CreateUser.js

代码语言:javascript
复制
import React, {useCallback, useContext, useEffect, useState} from 'react';
import {useHttp} from "../hooks/http.hook";
import Button from "../components/Button/Button";
import {AuthContext} from "../context/auth.context";
import {Formik} from "formik";

export const CreateUser = () => {
    const {token} = useContext(AuthContext);

    const {loading, request} = useHttp();

    const createUser = useCallback(async (body) => {
        try {
            const fetched = await request(`/api/user/create`, 'POST', body, {
                Authorization: `Bearer ${token}`
            });
        } catch (e) {console.log(e)}
    }, []);

    const handleCreate = (values, {resetForm}) => {
        console.log(values);
        createUser(values);
        
        // resetForm({});
    };

    return (
        <div className="wrapper">
            <div className="row">
                <div className="column small-12 text-center color-white mb_45">
                    <div className="custom-headline text text-48 font-bold">
                        <h1>
                            Crate user
                        </h1>
                    </div>
                </div>
            </div>

            
                <Formik
                    enableReinitialize
                    initialValues={{
                        name: '',
                        code: '',,
                        image: null
                    }}
                    onSubmit={handleCreate}
                >
                    {({
                          values,
                          errors,
                          touched,
                          handleBlur,
                          handleChange,
                          handleSubmit,
                          isSubmitting,
                          setFieldValue,
                          resetForm
                      }) => (
                        <form onSubmit={handleSubmit} className="row align-center">
                            <div className="column small-12 large-7">
                                <div className="form-item flex-container align-middle mb_20">
                                    <label className="text text-14 font-semibold font-uppercase text-right small-4">
                                        Photos
                                    </label>
                                    <input id="image" type="file" name="image" className="file_input"
                                           onChange={(event) => {
                                               setFieldValue("image", event.currentTarget.files[0]);
                                           }} />
                                </div>
                            </div>

                            <div className="column small-12 large-7">
                                <div className="form-item flex-container align-middle mb_20">
                                    <label className="text text-14 font-semibold font-uppercase text-right small-4">
                                        Name
                                    </label>
                                    <input
                                        className="text text-17 "
                                        type="text"
                                        name="name"
                                        onChange={handleChange}
                                        onBlur={handleBlur}
                                        value={values.name}
                                    />
                                </div>
                            </div>
                            <div className="column small-12 large-7">
                                <div className="form-item flex-container align-middle mb_20">
                                    <label className="text text-14 font-semibold font-uppercase text-right small-4">
                                        Code
                                    </label>
                                    <input
                                        className="text text-17"
                                        type="text"
                                        name="code"
                                        onChange={handleChange}
                                        onBlur={handleBlur}
                                        value={values.code}
                                    />
                                </div>
                            </div>

                            <div className="column small-12 mt_20">
                                <div className="btn_group flex-container flex-wrap align-middle align-center">
                                    <Button className="btn-lg radius-8" theme="blue"
                                            text={Submit} type="submit"
                                    />
                                </div>
                            </div>
                        </form>
                    )}
                </Formik>
        </div>
    )
};
EN

回答 3

Stack Overflow用户

发布于 2021-04-28 18:37:11

用formData用multer键" image“包装您的图像文件

代码语言:javascript
复制
upload.single('image')

前部

代码语言:javascript
复制
const handleCreate = async (values) => {
    try { 
      const body = new FormData();
      body.append( "image", values.image);
      ...
     
    } catch (err) {}
  };

并确保您的目标路径使用"dirname“

代码语言:javascript
复制
`${__dirname}/../client/public/uploads/`

根据您的目录路径更改此选项

票数 0
EN

Stack Overflow用户

发布于 2021-04-28 18:38:37

我有2-3条建议,在你的app.js文件中

代码语言:javascript
复制
router.post('/create', upload.single('image'), auth, async (req, res) => {
console.log(req.file);

在使用upload.single之前,您应该使用auth。

您应该使用{content type: multipart/form-data}发送带有POST请求的标头

票数 0
EN

Stack Overflow用户

发布于 2021-04-29 20:21:31

好的!我不知道这是为什么,但我找到了解决方案-我使用axios而不是fetch,当然FormData用于上传图像或文件,而且它是有效的!

希望这对其他人有帮助。谢谢你的回答。

代码语言:javascript
复制
const handleCreate = (values, {resetForm}) => {
        const formData = new FormData();

        formData.append('name', values.name);
        formData.append('code', values.code);
        formData.append('image', values.image);

        axios.post('/api/user/create', formData)
             .then(console.log)
             catch(console.error);
    
        resetForm({});
    };
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67305676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档