You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从React客户端上传文件至Node.js Express服务器?附客户端代码

Alright, let's get your file upload flow fully working. Here's a step-by-step complete implementation covering both your React frontend and Node.js Express backend.


Frontend (React Component)

First, let's polish your PopinForm component with proper error handling, upload logic, and user feedback:

import React, { PureComponent } from 'react';
// Assume your Root, Input, ButtonPopin components are imported correctly

class PopinForm extends PureComponent {
  constructor() {
    super();
    this.state = {
      file: null, // Initialize as null to easily check if a file is selected
      isError: {
        file: false,
      },
      uploadStatus: '' // Track upload success/failure for user feedback
    };
  }

  // Handle file selection and reset errors/status
  _handleFileChange = (e) => {
    const selectedFile = e.target.files[0];
    if (selectedFile) {
      this.setState({
        file: selectedFile,
        isError: { ...this.state.isError, file: false },
        uploadStatus: ''
      });
    }
  };

  // Handle file upload with async/await for cleaner async logic
  _handleUploadFile = async () => {
    const { file } = this.state;

    // Validate file selection first
    if (!file) {
      this.setState({
        isError: { ...this.state.isError, file: true },
        uploadStatus: ''
      });
      return;
    }

    try {
      // Create FormData to wrap the file (required for multipart file uploads)
      const formData = new FormData();
      formData.append('uploadedFile', file); // 'uploadedFile' matches the backend's expected field name

      const response = await fetch('http://localhost:5000/api/upload', {
        method: 'POST',
        body: formData
      });

      if (!response.ok) throw new Error('Upload failed to complete');

      const result = await response.json();
      this.setState({
        uploadStatus: `Success! File saved as: ${result.filename}`,
        file: null, // Reset file selection after successful upload
        isError: { ...this.state.isError, file: false }
      });
    } catch (error) {
      this.setState({
        uploadStatus: `Upload failed: ${error.message}`,
        isError: { ...this.state.isError, file: false }
      });
    }
  };

  render() {
    const { isError, uploadStatus, file } = this.state;
    return (
      <Root>
        <Input
          width="45%"
          type="file"
          onChange={this._handleFileChange}
          placeholder={file ? file.name : 'Select a file'}
        />
        {/* Show error if no file is selected on upload click */}
        {isError.file && (
          <span style={{ color: 'red', marginLeft: '10px' }}>
            Please select a file first
          </span>
        )}
        <ButtonPopin width="20%" onClick={this._handleUploadFile}>
          Upload
        </ButtonPopin>
        {/* Show upload status feedback */}
        {uploadStatus && (
          <p style={{ marginTop: '10px', color: uploadStatus.includes('Success') ? 'green' : 'red' }}>
            {uploadStatus}
          </p>
        )}
      </Root>
    );
  }
}

export default PopinForm;

Frontend Key Notes:

  • Uses FormData to properly format the file for upload (required for multipart/form-data requests)
  • Adds user feedback for both errors and successful uploads
  • Validates file selection before attempting upload
  • Cleans up state after successful upload to reset the form

Backend (Node.js Express Server)

We'll use multer (the standard Express middleware for file uploads) to handle incoming files, plus cors to fix cross-origin issues between React and Express.

1. Install Dependencies

First, install the required packages in your Node.js project:

npm install express multer cors

2. Server Code (server.js)

const express = require('express');
const multer = require('multer');
const cors = require('cors');
const path = require('path');
const fs = require('fs');

const app = express();
const PORT = 5000;

// Allow cross-origin requests from your React app (adjust origin if needed)
app.use(cors({ origin: 'http://localhost:3000' }));

// Configure multer to store files in an "uploads" folder
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const uploadDir = path.join(__dirname, 'uploads');
    // Auto-create the uploads folder if it doesn't exist
    if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir);
    cb(null, uploadDir);
  },
  filename: (req, file, cb) => {
    // Generate a unique filename to avoid overwriting existing files
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, `${file.fieldname}-${uniqueSuffix}${path.extname(file.originalname)}`);
  }
});

// Initialize multer with size and file type restrictions
const upload = multer({
  storage: storage,
  limits: { fileSize: 5 * 1024 * 1024 }, // Limit to 5MB files
  fileFilter: (req, file, cb) => {
    // Allow only specific file types (adjust as needed)
    const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    if (allowedTypes.includes(file.mimetype)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type. Only JPG, PNG, and PDF are allowed.'));
    }
  }
});

// Upload endpoint - handles single file uploads
app.post('/api/upload', upload.single('uploadedFile'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'No file was uploaded' });
  }

  // Return file details to the frontend
  res.status(200).json({
    message: 'File uploaded successfully',
    filename: req.file.filename,
    originalName: req.file.originalname,
    filePath: req.file.path
  });
});

// Handle multer errors (e.g., file too large, invalid type)
app.use((err, req, res, next) => {
  if (err instanceof multer.MulterError) {
    res.status(400).json({ error: err.message });
  } else if (err) {
    res.status(400).json({ error: err.message });
  } else {
    next();
  }
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

Backend Key Notes:

  • Uses cors to allow cross-origin requests from your React dev server (localhost:3000)
  • Configures multer to store files safely with unique filenames
  • Adds security restrictions (file size limit, allowed file types)
  • Handles errors gracefully and returns meaningful messages to the frontend

Testing the Flow

  1. Start your Express server: node server.js
  2. Start your React app (typically npm start, running on localhost:3000)
  3. Select a valid file (JPG/PNG/PDF, under 5MB) in your React form and click "Upload"
  4. Check the uploads folder in your Node.js project - your file should be there
  5. Verify the frontend shows a success message

内容的提问来源于stack exchange,提问作者french_dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:41:05