请求失败,状态代码为 500 错误。在 React 中制作 multiForm 数据的表单 post 时

Request failed with status code 500 error. When making form post of multiForm data in React

我在发送表单的文件/照片元素时遇到问题。当 POST 到达后端时,它看起来像是 posting OK 但是当我单击提交时表单屏幕没有做任何事情并且 Web 开发控制台标记“请求失败,状态代码为 500 " 错误。

如果我的后端 API 工作正常,这可能是 CORS 错误吗?路由的文件路径在我的后端路由文件夹中与我的表单组件上的 axios post 请求相同。此外,我的 IDE 终端正在标记来自 posting 的正确文本正在访问后端(我知道我需要修复用户 ID,但我可以自己完成)。该文件也进入了它要进入的文件夹,但没有进入我的 Postgres/pgAdmin 数据库。


    // state for the current field value
    const [article, setArticle] = useState({
        articleTitle: ``,
        articleTypeID: ``,
        articleContent: ``,
        // photos: undefined,
        userID: ``,
        error: ``,
    });

    const [photos, setPhotos] = useState({
        photos: null
    })

    const handleChange = (property) => (e) => {
        setArticle({
            // override the changed property and keep the rest
            ...article,
            [property]: e.target.value,
        });
    }

    const handleChangeInt = (property) => (e) => {
        setArticle({
            // override the changed property and keep the rest
            ...article,
            [property]: parseInt(e.target.value),
        });
    }

    const handleChangeFile = (photos) => (e) => {
        this.setState({
            selectedFiles: e.target.photos,
        })
    }
    // get access to dispatch
    const dispatch = useDispatch();

    // useEffect with an empty dependency array is the same as componentDidMount
    useEffect(() => {
        dispatch(requireFieldData());
    }, []);

    function handleSubmitArticle(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        const formData = new FormData();
        formData.append("articleTitle", article.articleTitle);
        formData.append("articleContent", article.articleContent);
        formData.append("userID", article.userID);
        formData.append("articleTypeID", article.articleTypeID);
        formData.append("photos", photos);
        axios.post("http://localhost:5002/api/article/createarticle", formData);
    }

    const classes = useStyles;

return (

    <div>

    <AppBar title="Enter your dive details"></AppBar>
    <form
        class="mt-4"
        id="articleForm"
        method="POST"
        enctype="multipart/form-data"
        onSubmit={handleSubmitArticle}>
        <>
            <Grid container spacing={3}
                  direction="row"
                  justify="center"
                  alignItems="center">
                <Grid item xs={10}>
                     <TextField
                      placeholder="Article-Title"
                      label="Article Title"
                      name="articleTitle"
                      margin="normal"
                      value={article.articleTitle}
                      onChange={handleChange("articleTitle")}
                      fullWidth/>
                </Grid>
                <Grid item xs={5}>
                    <FormControl className={classes.formControl}>
                        <TextField
                            placeholder="Author-User-Number"
                            label="AuthorUserNumber"
                            // defaultValue={props.user.userID}
                            margin="normal"
                            value={props.user.userID}
                            onChange={handleChangeInt("userID")}
                            fullWidth/>
                    </FormControl>
                </Grid>
                <Grid item xs={5}>
                    <FormControl className={classes.formControl}>
                        <PopulateDropdown
                            dataList={articleTypeList}
                            titleProperty={"articleType"}
                            valueProperty={"articleTypeID"}
                            label="Article Type"
                            placeholder="Select article type"
                            value={article.articleTypeID}
                            onChange={handleChangeInt("articleTypeID")}/>
                    </FormControl>
                </Grid>
                <Grid item xs={10}>
                    <FormControl fullWidth className={classes.formControl}>
                        <TextField
                            placeholder="Article Content"
                            label="ArticleContent"
                            name="articleContent"
                            value={article.articleContent}
                            onChange={handleChange("articleContent")}
                            multiline
                            rowsMax={6}
                            fullWidth/>
                    </FormControl>
                </Grid>
                <br />
                <Grid item xs={10}>
                    <div class="form-control">
                        <label for="photos">Photo Upload</label>
                        <input
                            type="file"
                            name="photos"
                            id="photos"
                            // value={article.photos}
                            onChange={(e) => {
                                setPhotos(e.target.files?.[0]);
                            }}
                                />
                    </div>
                </Grid>
                <br />
                <Grid item xs={8} md={6}>
                    <Button variant="primary" type="submit">
                        Submit</Button>
                </Grid>
            </Grid>
    </>
    </form>

更新

这可能与我的后端路由处理 formData 的方式有关吗?报错信息好像是axios错误。

//  create article
    app.post('/api/article/createarticle', upload.single("photos"), controller.createArticle);

更新

我已经将 Multer 添加到后端的路由中。除了上传部分,我还需要做任何其他事情吗?后端 API 完美运行,所以我认为这与后端无关。 Postman 表单数据 API 有效,所以我认为它可以正常处理表单数据。

const multer = require('multer');
const upload = multer({ dest: './assets/article/' })

module.exports = function(app) {

    app.post('/api/article/createarticle', upload.single("photos"), controller.createArticle);

后端似乎需要 Multer 之类的东西

问题:

从这条错误消息中可以看出,您的请求正文被解析为 JSON.

但是您发送的是 FormData,类型为 multipart/form-data

Express自带body-parser,无法处理multipart bodys:

This does not handle multipart bodies, due to their complex and typically large nature. For multipart bodies, you may be interested in the following modules:

  • busboy and connect-busboy
  • multiparty and connect-multiparty
  • formidable
  • multer

解决方案

  1. 发送JSON数据。你真的不需要表单数据,除非你有复杂的东西,比如文件输入

    axios.post("http://localhost:5002/api/article/createarticle", article)
    //== Plain JS object which will be converted to JSON string ========^
    
  2. 使用上面提到的可以处理表单数据的中间件。例如穆勒:

     var express = require('express')
     var app = express()
     var multer  = require('multer')
     var upload = multer()
    
     app.post('/createarticle', upload.none(), function (req, res, next) {
          // req.body contains the text fields
     })
    

我已经找到问题的原因。我的表单数据需要一些配置逻辑来处理如下表单数据。

function handleSubmitArticle(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        const formData = new FormData();
        formData.append("articleTitle", article.articleTitle);
        formData.append("articleContent", article.articleContent);
        formData.append("userID", article.userID);
        formData.append("articleTypeID", article.articleTypeID);
        formData.append("photos", photos);
        const config = {
            headers: {
                'content-type': 'multipart/form-data'
            }
        };
        axios.post("http://localhost:5002/api/article/createarticle", formData, config);
    }

我还需要添加一个方法来处理文件到我的照片输入的 onChange 部分。

<label for="photos">Photo Upload</label>
                        <input
                            type="file"
                            name="photos"
                            id="photos"
                            // value={article.photos}
                            onChange={(e) => {
                                console.log(e.target.files)
                                if (e.target.files && e.target.files[0]) {
                                    let img = e.target.files[0];
                                    setPhotos(img)
                                }
                                // setPhotos(e.target.photos.[0]);
                            }}
                                />