React上传文件至Node后端无法访问File对象问题
问题描述
将React前端<input type="file">提交的FileList传递到Node后端时,浏览器控制台显示文件列表已作为表单数据提交,但Node端遍历的文件对象为空,无法获取文件名完成上传操作。
相关代码与输出
Node.js路由代码
router.post("", (req, res) => { var tempFiles = req.body.files; var fileCount = Object.keys(tempFiles).length; console.log("FileList Keys: " + Object.keys(tempFiles)); console.log("Length: " + Object.keys(tempFiles).length); console.log("Object Length: " + Object.keys(tempFiles['0']).length); // Loop through files for (let i = 0; i < fileCount; i++) { let file = tempFiles[i]; console.log(tempFiles[i]); } }
Node控制台输出
FileList Keys: 0,1 Length: 2 Object Length: 0 {} {}
React表单代码
import React from 'react'; import axios from 'axios'; import {useState} from 'react'; import { useForm } from "react-hook-form"; import { Stack, Input ,Button, FormControl } from '@chakra-ui/react'; import BasicBanner from '../../core/components/banners/BasicBanner'; export default function UploadEvidence(props) { const [formMessage, setFormMessage] = useState(""); const { register, formState: { errors }, handleSubmit } = useForm(); const onError = (errors, e) => console.log(errors, e); const onSubmit = (data, e) => { console.log(data); axios.post('http://localhost:5000/api/uploads', data) .then(function (response) { console.log(response); setFormMessage("Upload successful"); }) .catch(function (error) { console.log(error); setFormMessage("Error uploading"); }); } return ( <form onSubmit={handleSubmit(onSubmit, onError)} enctype="multipart/form-data"> <Stack spacing="10"> {formMessage && <BasicBanner message={formMessage} /> } <Input type="file" accept="pdf/*" multiple {...register("files", {required: true })} aria-invalid={errors.files ? "true" : "false"} /> </Stack> <FormControl mt={4}> <Button type="submit" colorScheme='blue'>Save</Button> </FormControl> </form> ) }
Node server.js代码
const express = require('express') const PORT = process.env.PORT || 5000 const app = express() const bodyParser = require("body-parser"); const fileupload = require("express-fileupload"); var cors = require('cors'); app.use(cors()); app.use(fileupload()); app.use(express.static("files")); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // ... Routes ...
问题原因
- 数据序列化失效:axios默认将请求数据序列化为JSON格式,但File对象无法被JSON序列化,传递到后端后会被转化为空对象
{}。 - 后端读取位置错误:你使用了
express-fileupload中间件,上传的文件会被解析到req.files对象中,而非req.body,但当前代码从req.body.files读取数据,自然无法拿到有效文件信息。
解决方案
前端修改:使用FormData传递文件
在onSubmit函数中手动构建FormData,将文件对象正确存入后再发送请求,同时设置对应请求头:
const onSubmit = (data, e) => { const formData = new FormData(); // 遍历FileList,将每个文件添加到FormData中 Array.from(data.files).forEach(file => { formData.append('files', file); }); axios.post('http://localhost:5000/api/uploads', formData, { headers: { 'Content-Type': 'multipart/form-data' } }) .then(function (response) { console.log(response); setFormMessage("Upload successful"); }) .catch(function (error) { console.log(error); setFormMessage("Error uploading"); }); }
后端修改:从req.files读取文件
调整路由代码,从req.files中获取上传的文件:
router.post("", (req, res) => { // 处理单个/多个文件的情况:express-fileupload在单文件时返回对象,多文件时返回数组 const tempFiles = req.files?.files || []; const filesArray = Array.isArray(tempFiles) ? tempFiles : [tempFiles]; console.log("文件数量: " + filesArray.length); // 遍历文件获取信息并处理 filesArray.forEach((file, index) => { console.log(`第${index+1}个文件名:`, file.name); // 执行文件保存操作,示例:file.mv(`./uploads/${file.name}`) }); res.status(200).json({message: "文件接收成功"}); });
额外注意事项
- 前端
<form>标签的enctype="multipart/form-data"属性可保留,手动构建FormData时请求头会覆盖该属性,但不影响功能。 - 确保
express-fileupload中间件已正确安装并启用,无需调整其与bodyParser的注册顺序。
内容的提问来源于stack exchange,提问作者Oliver Trampleasure
相关产品推荐
相关产品推荐

