React中如何获取上传文件的绝对路径并传入MongoDB?
React上传文件到MongoDB(GridFS)的正确方案
你当前的思路存在本质问题——浏览器出于安全限制,永远不会向网页暴露本地文件的绝对路径,所以前端根本无法获取到C:\\Users\\name\\work\\files\\file.json这类路径,必须换一种文件上传的方式:直接将文件内容通过FormData传给后端,再由后端将文件流写入GridFS。
一、后端改造(使用multer处理文件上传)
首先安装multer(处理multipart/form-data的中间件),然后修改路由逻辑,直接接收前端传来的文件流写入GridFS:
单文件上传后端代码
const multer = require('multer'); const { GridFSBucket } = require('mongodb'); // 配置multer使用内存存储(也可根据需求改用磁盘存储) const storage = multer.memoryStorage(); const upload = multer({ storage: storage }); // 假设已存在MongoDB连接实例client,替换为你的数据库名 const bucket = new GridFSBucket(client.db('your-db-name')); const addFile = async (req, res) => { try { const file = req.file; if (!file) { return res.status(400).json({ error: '未选择文件' }); } // 创建GridFS上传流,保留文件名和MIME类型 const uploadStream = bucket.openUploadStream(file.originalname, { contentType: file.mimetype }); // 将文件Buffer写入流 uploadStream.end(file.buffer); uploadStream.on('finish', () => { res.json({ id: uploadStream.id }); }); uploadStream.on('error', (err) => { res.status(500).json({ error: '文件上传失败', details: err.message }); }); } catch (err) { res.status(500).json({ error: '服务器错误', details: err.message }); } }; // 修改路由,添加multer中间件处理单文件 router.post('/fs', upload.single('file'), addFile);
多文件上传后端代码
如果需要支持多选文件,将中间件和处理逻辑改为多文件模式:
const addFiles = async (req, res) => { try { const files = req.files; if (!files || files.length === 0) { return res.status(400).json({ error: '未选择文件' }); } const resultIds = []; for (const file of files) { const uploadStream = bucket.openUploadStream(file.originalname, { contentType: file.mimetype }); uploadStream.end(file.buffer); await new Promise((resolve, reject) => { uploadStream.on('finish', () => { resultIds.push(uploadStream.id); resolve(); }); uploadStream.on('error', reject); }); } res.json({ ids: resultIds }); } catch (err) { res.status(500).json({ error: '服务器错误', details: err.message }); } }; // 支持最多10个文件上传,可修改数字调整上限 router.post('/fs/multi', upload.array('files', 10), addFiles);
二、React前端改造
使用FormData封装文件,通过fetch或axios发送请求:
单文件上传组件
import { useState } from 'react'; const SingleFileUpload = () => { const [selectedFile, setSelectedFile] = useState(null); const handleFileChange = (e) => { setSelectedFile(e.target.files[0]); }; const handleUpload = async () => { if (!selectedFile) return; const formData = new FormData(); formData.append('file', selectedFile); try { const response = await fetch('/api/fs', { method: 'POST', body: formData }); const data = await response.json(); console.log('文件上传成功,ID:', data.id); } catch (err) { console.error('上传失败:', err); } }; return ( <div> <input type="file" onChange={handleFileChange} /> <button onClick={handleUpload} disabled={!selectedFile}>上传文件</button> </div> ); }; export default SingleFileUpload;
多文件上传组件
import { useState } from 'react'; const MultiFileUpload = () => { const [selectedFiles, setSelectedFiles] = useState([]); const handleFileChange = (e) => { setSelectedFiles([...e.target.files]); }; const handleUpload = async () => { if (selectedFiles.length === 0) return; const formData = new FormData(); selectedFiles.forEach(file => { formData.append('files', file); }); try { const response = await fetch('/api/fs/multi', { method: 'POST', body: formData }); const data = await response.json(); console.log('文件上传成功,IDs:', data.ids); } catch (err) { console.error('上传失败:', err); } }; return ( <div> <input type="file" multiple onChange={handleFileChange} /> <button onClick={handleUpload} disabled={selectedFiles.length === 0}>上传选中文件</button> </div> ); }; export default MultiFileUpload;
关键说明
浏览器的安全策略严格禁止网页获取本地文件的绝对路径,目的是防止恶意网站窃取用户本地文件系统信息。前端拿到的File对象仅包含文件名、大小、MIME类型等元数据,无法获取本地路径,因此后端依赖前端传路径的逻辑从根本上不可行。
内容的提问来源于stack exchange,提问作者Ruo
相关产品推荐
相关产品推荐

