如何在Express中读取非本地File对象?fetch文件上传疑问
问题分析与解决方案
你的代码问题出在哪?
你直接把File对象拼进JSON字符串里,JSON只能序列化字符串、数字、布尔、数组、普通对象这类基本类型,File是复杂的二进制对象,转成字符串就会变成[object File],后端自然拿不到实际的文件内容。
能不能不用FormData上传文件?
能,但非常不推荐。
HTTP协议里,上传二进制文件的标准方式是用multipart/form-data格式(也就是FormData对应的格式)。如果非要不用FormData,只能把文件转成Base64编码后放进JSON里,但这种方式有明显缺点:
- Base64编码会让文件体积增大30%,传输效率更低
- 处理大文件时,前端转Base64会占用大量内存,容易导致页面卡顿
- 后端需要额外解码,增加服务器开销
推荐的正确实现(FormData方式)
前端代码修改
subBtn.addEventListener('click', requestCreate); async function requestCreate(e) { e.preventDefault(); try { const formData = new FormData(); // 添加普通字段 formData.append('title', name.value); formData.append('body', email.value); // 添加文件 if (file.files[0]) formData.append('file', file.files[0]); if (file.files[1]) formData.append('file2', file.files[1]); const res = await fetch('http://localhost:3000/', { method: 'POST', body: formData // 不要手动设置Content-Type,浏览器会自动添加带边界的multipart/form-data头 }); if (!res.ok) throw Error(res.statusText); } catch (error) { console.log(error); } }
后端代码修改
需要安装multer中间件来解析multipart/form-data格式的请求:
npm install multer
然后修改后端代码:
const express = require('express'); const multer = require('multer'); const app = express(); // 配置multer,这里用内存存储,也可以配置成存储到磁盘 const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); // 使用upload中间件解析文件,fields指定接收的文件字段名 app.post('/', upload.fields([{ name: 'file' }, { name: 'file2' }]), (req, res) => { // 普通字段在req.body里 console.log('title:', req.body.title); console.log('body:', req.body.body); // 文件在req.files里 console.log('file:', req.files.file?.[0]); // 文件对象,包含buffer、originalname等属性 console.log('file2:', req.files.file2?.[0]); res.send({ name: 'hello world' }); }); app.listen(3000, () => console.log('Server running on port 3000'));
不推荐的Base64方式(满足不用FormData的需求)
前端代码
subBtn.addEventListener('click', requestCreate); // 工具函数:把File转成Base64 function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(file); }); } async function requestCreate(e) { e.preventDefault(); try { // 把文件转成Base64 const fileBase64 = file.files[0] ? await fileToBase64(file.files[0]) : null; const file2Base64 = file.files[1] ? await fileToBase64(file.files[1]) : null; const obj = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: name.value, body: email.value, file: fileBase64, file2: file2Base64 }) }; const res = await fetch('http://localhost:3000/', obj); if (!res.ok) throw Error(res.statusText); } catch (error) { console.log(error); } }
后端代码
const express = require('express'); const fs = require('fs'); const path = require('path'); const app = express(); app.use(express.json({ limit: '10mb' })); // 要设置更大的请求体限制,因为Base64体积大 app.post('/', (req, res) => { const { title, body, file, file2 } = req.body; console.log('title:', title); console.log('body:', body); // 解码Base64并保存文件 if (file) { // 去掉Base64前缀(data:image/png;base64,) const base64Data = file.replace(/^data:.+;base64,/, ''); const buffer = Buffer.from(base64Data, 'base64'); fs.writeFileSync(path.join(__dirname, 'uploaded-file.png'), buffer); } res.send({ name: 'hello world' }); }); app.listen(3000, () => console.log('Server running on port 3000'));
内容的提问来源于stack exchange,提问作者Mohammad Yasin
相关产品推荐
相关产品推荐

