【问题标题】:JS fetch API cannot passing file in the body (Frontend: React, backend: Express)JS fetch API 无法在正文中传递文件(前端:React,后端:Express)
【发布时间】:2021-01-04 08:58:06
【问题描述】:

这个问题解决了

感谢所有花时间帮助我的人,根据你的想法,我解决了这个问题,如果你访问这个问题,请忽略它,祝你有美好的一天

我正在使用 ExpressJS(服务器)和 ReactJS(客户端)来构建我的网站,我需要获取 API 以将数据发送到服务器,我刚刚体验过仅将文本传递到 fetch API 的主体,但现在我有发送文件的任务。这是我的代码:

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Button, TextField } from '@material-ui/core';
import IconButton from '@material-ui/core/IconButton';

import AttachFileIcon from '@material-ui/icons/AttachFile';

const useStyles = makeStyles((theme) => ({
    root: {
        '& > *': {
            margin: theme.spacing(1),
        },
    },
    input: {
        display: 'none',
    },
}));

const ModalContent = () => {
    const classes = useStyles();

    const [course, setCourse] = useState({
        classname: '',
        schoolYear: '',
        excel: '',
    });

    const [selectedExcel, setSelectedExcel] = useState('');

    const handleSubmit = (event) => {
        event.preventDefault();
        var { classname, excel, schoolYear } = course;
    
        fetch('http://localhost:5000/classes/', {
            method: 'POST',
            headers: {
                Accept: 'application/json',
                'content-type': 'application/json; charset=UTF-8',
            },
            body: JSON.stringify({classname, schoolYear, excel}),
        })
            .then((response) => {
                return response.json();
            })
            .then((json) => {
                console.log(json);
            })
            .catch((error) => {
                console.error(error);
            });
    };

    return (
        <div className={classes.root}>
            <form enctype="multipart/form-data">
                <img src="http://dangkyhoc.daotao.vnu.edu.vn/Images/logo.png" alt="" style={{ height: '65px' }} />
                <TextField
                    type="text"
                    label="Class Name"
                    name="classname"
                    fullWidth
                    onChange={(event) => setCourse({ ...course, classname: event.target.value })}
                />
                <br />

                <TextField
                    type="text"
                    label="SchoolYear"
                    name="schoolYear"
                    fullWidth
                    onChange={(event) => setCourse({ ...course, schoolYear: event.target.value })}
                />

                <input
                    accept="image/*"
                    className={classes.input}
                    id="icon-button-file"
                    type="file"
                    accept=".xlsx"
                    onChange={(event) => {
                        setCourse({ ...course, excel: event.target.files[0] });
                        setSelectedExcel(event.target.files[0].name);
                    }}
                />

                <label htmlFor="icon-button-file">
                    <IconButton color="primary" aria-label="upload picture" component="span">
                        <AttachFileIcon fontSize="large" /> {JSON.stringify(selectedExcel)}
                    </IconButton>
                </label>
                <br />

                <Button color="primary" variant="contained" fullWidth onClick={handleSubmit} type="submit">
                    Add Class
                </Button>
            </form>
        </div>
    );
};

export default ModalContent;

我需要在 fetch API 的主体中传递“课程”的属性,我尝试调试器测试单击“添加类”按钮后是否为类名、schoolYear 和 excel 赋值,他们确实这样做了

所以我去服务器(ExpressJs)检查服务器端得到了什么,结果如下:

如您所见,他们获得了所有文本类型的属性,除了其类型为文件的 excel,它返回一个空对象。我认为这只是语法,感谢您花时间帮助我,这对我来说意义重大,因为这是我的论文,非常感谢您

更新:这是我在 ExpressJS 中的 app.js

const express = require("express");
const app = express();
const morgan = require("morgan");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");

const consultantRoutes = require("./api/routes/consultant");
const studentRoutes = require("./api/routes/students");
const classRoutes = require("./api/routes/class");
const userRoutes = require("./api/routes/user");

mongoose.connect(
  'mongodb+srv://conor_9tails:Mongoatlas123@cluster0-xcpy1.mongodb.net/uet-thesis?retryWrites=true&w=majority',
  {
    useUnifiedTopology: true,
    useNewUrlParser: true,
    useUnifiedTopology: false, // sau 30000ms mongo server sẽ tự động đóng
    useFindAndModify: false,
    useUnifiedTopology: true
  }
)

mongoose.Promise = global.Promise

mongoose.connection.on('connected', () => {
  console.log('database: uet-thesis')
})


app.use(morgan("dev"));
app.use('/uploads', express.static('uploads'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept, Authorization"
  );
  if (req.method === "OPTIONS") {
    res.header("Access-Control-Allow-Methods", "PUT, POST, PATCH, DELETE, GET");
    return res.status(200).json({});
  }
  next();
});

// Routes which should handle requests
app.use("/consultants", consultantRoutes);
app.use("/students", studentRoutes);
app.use("/classes", classRoutes);
app.use("/users", userRoutes);

app.use((req, res, next) => {
  const error = new Error("Not found");
  error.status = 404;
  next(error);
});

app.use((error, req, res, next) => {
  res.status(error.status || 500);
  res.json({
    error: {
      message: error.message
    }
  });
});

module.exports = app;

【问题讨论】:

  • 您在客户端上尝试过console.log(excel) 吗?
  • 感谢您花时间帮助我,根据您的想法,我解决了这个问题

标签: reactjs express frontend backend fetch-api


【解决方案1】:

要上传文件,您需要使用 FormData:

const { classname, excel, schoolYear } = course;
const formData = new FormData();
formData.append("classname", classname);
formData.append("excel", excel);
formData.append("schoolYear", schoolYear);

fetch('http://localhost:5000/classes/', {
    method: "POST",
    headers: {
      Accept: "application/json",
    },
    body: formData,
})

更新: 为了从后端接收文件,您需要一个中间件。这是我测试的结果,它按预期工作:

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const fileUpload = require("express-fileupload");
const app = express();

app.use(
  fileUpload({
    createParentPath: true,
  })
);
app.use(cors());
app.use(bodyParser.json());
app.route("/upload").post((req, res, next) => {
  console.log(req.files); // the incoming file can be accessed via req.files
  // upload the file

});

const server = app.listen(3030, () => {
  console.log("Listening on port %d", server.address().port);
});

如您所见,我使用了express-fileupload,这是一个第三方包来接收来自客户端的 blob。

还有一件事:确保您没有将content-type 与您的请求一起传递,因为它不需要。

【讨论】:

  • 我按照你的建议做了,它收到了 classname 和 schoolYear,而不是 excel
  • 感谢您花时间帮助我,根据您的想法,我解决了这个问题
【解决方案2】:

您需要在 That 中进行 2 处更改

第一

const { classname, excel, schoolYear } = course;
const formData = new FormData();
formData.append("classname", classname);
formData.append("excel", excel);
formData.append("schoolYear", schoolYear);

fetch('http://localhost:5000/classes/', {
    method: "POST",
    headers: {
      Accept: "multipart/form-data"
    },
    body: formData,
})

安装“express-fileupload”
app.js 中的第二个

const fileUpload = require('express-fileupload');

 app.use(fileUpload());

app.use(function (req, res, next) {
    //res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
    res.header("Access-Control-Allow-Origin", "*");
    res.header('Access-Control-Allow-Credentials', true);
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,authorization,accessToken," +
        "lat lng,app_version,platform,ios_version,countryISO,Authorization");
    res.setHeader('Access-Control-Allow-Methods', 'POST,GET,PUT,DELETE,OPTIONS');
    next();
});

console.log(req.files);

【讨论】:

  • 我按照你的建议做了,它收到了 classname 和 schoolYear,而不是 excel
  • @TamDo 请控制台console.log(req.files); 然后检查。
  • 感谢您花时间帮助我,根据您的想法,我解决了这个问题
猜你喜欢
  • 2022-11-20
  • 1970-01-01
  • 2020-12-22
  • 2019-11-13
  • 1970-01-01
  • 2018-01-20
  • 1970-01-01
  • 2022-01-21
  • 2017-11-22
相关资源
最近更新 更多