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

如何将客户端图片上传至NodeJS服务器并在服务器本地存储?

嘿,看你在把图片上传到Node.js服务器的过程中遇到了不少麻烦,试过jQuery、XHR还有表单都没搞定?别慌,我帮你捋清楚问题出在哪,再给你一套能直接跑通的方案~

解决Node.js服务器接收客户端图片上传并本地存储的问题

先说说你可能踩的坑

你之前尝试的方法没成功,大概率是这几个原因:

  • 没正确用FormData封装文件:直接传img元素或者图片URL是不行的,服务器需要的是二进制文件数据,必须用FormData来包装
  • 服务器没配置文件上传中间件:Express本身不处理multipart/form-data格式的请求,得用multer这类工具来解析
  • 请求头设置错误:比如用XHR时手动设置了Content-Type,导致浏览器没法自动添加正确的boundary分隔符

完整解决方案:客户端+服务器代码

我会给你三种客户端上传方式,搭配Express+Multer的服务器代码,你可以按需选择。

第一步:服务器端配置(核心!)

首先安装依赖:

npm install express multer cors

然后创建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();

// 允许跨域请求(如果客户端和服务器不同域名的话需要)
app.use(cors());

// 配置multer的存储规则
const storage = multer.diskStorage({
  // 上传文件保存的目录,自动创建不存在的目录
  destination: (req, file, cb) => {
    const uploadDir = path.join(__dirname, 'uploads');
    fs.mkdirSync(uploadDir, { recursive: true });
    cb(null, uploadDir);
  },
  // 自定义文件名,避免重复
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, `${file.fieldname}-${uniqueSuffix}${path.extname(file.originalname)}`);
  }
});

// 初始化multer,限制文件类型为图片,最大5MB
const upload = multer({
  storage: storage,
  limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
  fileFilter: (req, file, cb) => {
    const allowedTypes = /jpeg|jpg|png|gif/;
    const extIsValid = allowedTypes.test(path.extname(file.originalname).toLowerCase());
    const mimeTypeIsValid = allowedTypes.test(file.mimetype);
    
    if (extIsValid && mimeTypeIsValid) {
      cb(null, true);
    } else {
      cb(new Error('只允许上传JPG/PNG/GIF格式的图片!'));
    }
  }
});

// 处理图片上传的POST接口
app.post('/upload', upload.single('image'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ message: '请选择要上传的图片' });
  }
  
  // 文件已经成功保存到uploads目录,返回文件信息
  res.json({
    message: '图片上传成功',
    fileInfo: {
      filename: req.file.filename,
      savePath: req.file.path,
      size: `${(req.file.size / 1024).toFixed(2)}KB`
    }
  });
});

// 错误处理中间件
app.use((err, req, res, next) => {
  res.status(400).json({ message: err.message });
});

// 启动服务器
const PORT = 3000;
app.listen(PORT, () => {
  console.log(`服务器运行在 http://localhost:${PORT}`);
});

第二步:客户端上传方式

方式1:原生HTML表单(最简单,适合测试)

直接写个表单,不需要JS就能上传:

<form action="http://localhost:3000/upload" method="POST" enctype="multipart/form-data">
  <input type="file" name="image" accept="image/*" required>
  <button type="submit">上传图片</button>
</form>

方式2:原生XMLHttpRequest(自定义逻辑友好,比如加进度条)

// 获取文件选择框
const fileInput = document.querySelector('input[type="file"]');

fileInput.addEventListener('change', (e) => {
  const selectedFile = e.target.files[0];
  if (!selectedFile) return;

  // 用FormData包装文件
  const formData = new FormData();
  formData.append('image', selectedFile); // 'image'要和服务器的upload.single('image')参数一致

  const xhr = new XMLHttpRequest();
  xhr.open('POST', 'http://localhost:3000/upload');

  // 可选:监听上传进度
  xhr.upload.addEventListener('progress', (progressEvent) => {
    if (progressEvent.lengthComputable) {
      const progressPercent = (progressEvent.loaded / progressEvent.total) * 100;
      console.log(`上传进度:${progressPercent.toFixed(2)}%`);
      // 这里可以更新页面上的进度条
    }
  });

  // 监听请求完成
  xhr.onload = () => {
    if (xhr.status === 200) {
      const result = JSON.parse(xhr.responseText);
      console.log('上传成功!', result);
    } else {
      const error = JSON.parse(xhr.responseText);
      console.error('上传失败:', error.message);
    }
  };

  // 发送请求,不要手动设置Content-Type!
  xhr.send(formData);
});

方式3:jQuery上传(如果你习惯用jQuery)

$('input[type="file"]').on('change', function() {
  const selectedFile = $(this)[0].files[0];
  if (!selectedFile) return;

  const formData = new FormData();
  formData.append('image', selectedFile);

  $.ajax({
    url: 'http://localhost:3000/upload',
    type: 'POST',
    data: formData,
    processData: false, // 必须设为false,否则jQuery会把FormData转成字符串
    contentType: false, // 必须设为false,让浏览器自动处理Content-Type
    xhr: function() {
      // 可选:监听上传进度
      const xhr = $.ajaxSettings.xhr();
      if (xhr.upload) {
        xhr.upload.addEventListener('progress', (e) => {
          if (e.lengthComputable) {
            const percent = (e.loaded / e.total) * 100;
            console.log(`上传进度:${percent.toFixed(2)}%`);
          }
        });
      }
      return xhr;
    },
    success: function(response) {
      console.log('上传成功!', response);
    },
    error: function(xhr) {
      const error = JSON.parse(xhr.responseText);
      console.error('上传失败:', error.message);
    }
  });
});

针对你代码片段的特殊处理:上传img元素对应的图片

你之前的代码是创建了img元素加载本地图片,想上传这个图片的话,需要把img转成Blob再包装到FormData里:

let img = document.createElement("img");
img.src = "./public/assets/img.png";
img.crossOrigin = "anonymous"; // 如果图片是跨域的必须加这个
img.addEventListener("load", (e) => {
  addParkingSource(img);
});

function addParkingSource(img) {
  // 创建canvas把img转成Blob
  const canvas = document.createElement('canvas');
  canvas.width = img.width;
  canvas.height = img.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);

  // 转成Blob并上传
  canvas.toBlob((blob) => {
    const formData = new FormData();
    formData.append('image', blob, 'img.png'); // 第三个参数是保存的文件名

    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://localhost:3000/upload');
    xhr.onload = () => {
      if (xhr.status === 200) {
        console.log('图片上传成功!');
      } else {
        console.error('上传失败');
      }
    };
    xhr.send(formData);
  }, 'image/png'); // 指定图片格式
}

最后测试步骤

  1. 启动服务器:node server.js
  2. 打开客户端页面,选择图片上传
  3. 查看服务器根目录下的uploads文件夹,应该能看到上传的图片

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:19:01