如何将客户端图片上传至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'); // 指定图片格式 }
最后测试步骤
- 启动服务器:
node server.js - 打开客户端页面,选择图片上传
- 查看服务器根目录下的
uploads文件夹,应该能看到上传的图片
内容的提问来源于stack exchange,提问作者DomainFlag
相关产品推荐
相关产品推荐

