使用 FormData() 时发布请求时请求正文为空

时间:2021-03-27 05:57:11

标签: node.js reactjs

我正在尝试将表单数据从 react 发送到 express 服务器。发送 json 有效负载时,我得到了预期的结果。但是,当使用 formdata.append 发送数据时,我得到了空的请求正文。

针对类似问题,我尝试了此处发布的各种解决方案,但似乎对我没有任何效果。

希望有人能帮忙

app.js

require('./database/db')
const express = require('express')
const cors = require('cors')
const userRouter = require('./routes/user')
const menuRouter = require('./routes/menu')

const app = express()

app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cors())

app.use(express.static('public'))

app.use(userRouter)
app.use(menuRouter)

app.listen(9000, () => console.log('Server started at port: 9000'))

我想打电话的路线

router.post(
    '/addMenu',
    [
        check('name', 'Menu name is required!').not().isEmpty(),
        check('price', 'Price is required!').not().isEmpty(),
        check('category', 'Category is required!').not().isEmpty(),
    ],
    verifyAuth,
    (req, res) => {
        console.log(req.body)
// body is empty here
})

react bootstrap 表单

import { Component } from 'react'
import axios from '../axios'
import { Link } from 'react-router-dom'
import { Button, Form, Card } from 'react-bootstrap'

export default class AddMenu extends Component {
    constructor(props) {
        super(props)
        this.state = {
            name: '',
            price: '',
            category: '',
            image: '',
        }

        this.inputHandler = this.inputHandler.bind(this)
        this.inputHandler = this.inputHandler.bind(this)
        this.addMenu = this.addMenu.bind(this)
    }

    inputHandler = (e) => {
        this.setState({
            [e.target.name]: e.target.value,
        })
    }
    fileHandler = (e) => {
        this.setState({
            image: e.currentTarget.files[0],
        })
    }
    addMenu = (e) => {
        e.preventDefault()
        const { name, price, category, image } = this.state

        const data = new FormData()

        data.append('name', name)
        data.append('price', price)
        data.append('category', category)
        data.append('file', image)

        axios
            .post('/addMenu', data)
            .then((response) => {
                if (response.data.success) {
                    alert(response.data.menu)
                } else {
                    alert('something went wrong')
                }
            })
            .catch()
    }

    render() {
        return (
            <div className='col-lg-12 col-centered' style={{ height: '44rem' }}>
                <Card
                    style={{
                        width: '20rem',
                        marginLeft: '420px',
                        marginTop: '80px',
                        float: 'left',
                        height: '34rem',
                    }}
                >
                    <Card.Img
                        variant='top'
                        src='https://image.freepik.com/free-vector/food-delivery-service-fast-food-delivery-scooter-delivery-service-illustration_67394-869.jpg'
                    />
                    <Card.Body>
                        <Card.Title>Add Menu</Card.Title>
                        <Card.Text>
                            Although a great restaurant experience must include great food, a bad restaurant experience can be achieved through bad service alone.
                            Ideally, service is invisible.
                        </Card.Text>
                        <Button as={Link} to='/' variant='info'>
                            Go to Home
                        </Button>
                    </Card.Body>
                </Card>
                <Card
                    style={{
                        width: '22rem',
                        marginTop: '78px',
                        float: 'left',
                        height: '34rem',
                    }}
                >
                    <Form className='add-menu' onSubmit={this.addMenu}>
                        <h2>Add Menu</h2>
                        <Form.Group controlId='formBasicName'>
                            <Form.Label>Restaurant Name</Form.Label>
                            <Form.Control
                                type='text'
                                name='name'
                                placeholder='Enter Restaurant Name'
                                value={this.state.name}
                                onChange={(event) => this.inputHandler(event)}
                            />
                        </Form.Group>

                        <Form.Group controlId='formBasicPrice'>
                            <Form.Label>Enter Price</Form.Label>
                            <Form.Control type='text' name='price' placeholder='Price' value={this.state.price} onChange={(event) => this.inputHandler(event)} />
                        </Form.Group>

                        <Form.Group controlId='formBasicCategory'>
                            <Form.Label>Enter Category</Form.Label>
                            <Form.Control
                                name='category'
                                type='text'
                                placeholder='Enter Menu Category'
                                value={this.state.category}
                                onChange={(event) => this.inputHandler(event)}
                            />
                        </Form.Group>

                        <Form.Group controlId='formBasicImage'>
                            <Form.Label>Enter Category</Form.Label>
                            <Form.Control name='image' type='file' onChange={this.fileHandler} />
                        </Form.Group>

                        <Button className='btn-lg btn-block' variant='info' type='submit'>
                            Add Menu
                        </Button>
                    </Form>
                </Card>
                <br />
                <br />
                <br />
            </div>
        )
    }
}

路由/菜单实现

const router = require('express').Router()
const { verifyAuth } = require('../middleware/auth')
const upload = require('../middleware/fileUpload')
const Menu = require('../models/Menu')
const { check, validationResult } = require('express-validator')

// add a menu item
router.post(
    '/addMenu',
    [
        check('name', 'Menu name is required!').not().isEmpty(),
        check('price', 'Price is required!').not().isEmpty(),
        check('category', 'Category is required!').not().isEmpty(),
    ],
    verifyAuth,
    (req, res) => {
        console.log(req.body)
        if (req.authUser.userType === 'Restaurant') {
            const validationErr = validationResult(req)
            if (validationErr.isEmpty()) {
                let image = null
                const { name, price, category } = req.body
                if (req.file) {
                    upload(req, res, (err) => {
                        if (err) {
                            response.status(500).json({ success: false, message: err })
                        } else {
                            image = req.file.filename
                        }
                    })
                }
                const newMenu = new Menu({ name, price, category, addedBy: req.authUser._id, image })
                newMenu
                    .save()
                    .then((menu) => res.status(201).json({ success: true, message: 'Menu added', menu }))
                    .catch((error) => res.status(500).json({ success: false, message: error.message }))
            } else {
                res.status(400).json({ success: false, errors: validationErr.array() })
            }
        } else {
            res.status(403).json({ success: true, message: 'Insufficient privileges' })
        }
    }
)

// get all menu items
router.get('/menus', (req, res) => {
    Menu.find()
        .populate('addedBy', '-_id name')
        .then((menus) => res.status(200).json({ success: true, menus }))
        .catch((error) => res.status(500).json({ success: false, message: error.message }))
})

module.exports = router

即使在 Postman x-www-form-urlencoded 发送数据但 form-data

3 个答案:

答案 0 :(得分:0)

您应该将请求标头的 Content-Type 设置为 Content-Type: application/x-www-form-urlencoded 这将允许 express 访问您在正文中的表单数据

要在 axios 中设置标题,您可以像这样执行

const config = {
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
};

并且您使用这样的标头设置向后端执行请求

axios.post('/addMenu', data, config)
    .then({ /*...*/});

答案 1 :(得分:0)

在您的 axios 请求中,您需要在标头中指定内容类型 的请求。我通常也做的是将我的 agrs 指定为一个对象 用于注释目的

像这样:

axios({
  method: 'post',
  url: '/addMenu',
  data: data,
  headers: { 'Content-Type': 'application/json' },
})
  .then((response) => {
    if (response.data.success) {
      alert(response.data.menu)
    } else {
      alert('something went wrong')
    }
  })
  .catch((error) => {
    //handle error
    console.log(error);
  });

编辑

我刚刚注意到您也在尝试发送文件...哈哈

要通过express发送文件,您需要获取名为multer的包来为您处理文件上传

npm i --save multer

然后在配置服务器时添加它

const multer = require('multer');

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());

app.use(multer().any());

完成后,在 axios 端的请求中,这样做:


axios({
  method: 'post',
  url: '/addMenu',
  data: data,
  headers: { 'Content-Type': 'multipart/form-data' },
})
  .then((response) => {
    if (response.data.success) {
      alert(response.data.menu)
    } else {
      alert('something went wrong')
    }
  })
  .catch((error) => {
    //handle error
    console.log(error);
  });

最后,为了处理您服务器上的文件,它们将显示在请求中 像这样的对象:

request.files // which will be an array of file objects

请试试这个...我知道它很长,但我曾经遇到过这个问题并使用了这个解决方案

答案 2 :(得分:0)

如果没有通过这样的路由提供给它的文件,表单数据将获得空对象。

function myFunction() {
    var pathname = window.location.pathname;  
    var lang = pathname.split("/")[1];
    var page = pathname.split("/")[2];

    if ((lang = "fr/")) {
        location.replace(window.location.origin + "/" + page);
    }
}

不知道是什么导致了这种行为,但是当您发送一些文件(如图像文档等)时使用表单数据。