ExpressJS file-upload无法获取webkitRelativePath的解决办法咨询
我完全理解你的需求——想要通过上传文件的原始目录结构来创建对应文件夹,但目前req.files里只返回了文件名,完全看不到路径信息。结合你提供的截图(包括文件对象、HTTP请求和req.files的内容)来看,问题核心在于前端是否正确传递了路径信息以及后端是否配置了正确的解析逻辑,下面是具体的解决方案:
为什么拿不到webkitRelativePath?
首先要明确:浏览器出于安全限制,不会直接暴露文件的完整本地绝对路径。但webkitRelativePath是个例外——只有当你上传整个目录(而非单个文件)时,浏览器才会在File对象中添加这个属性,它表示文件相对于上传目录的相对路径(比如docs/reports/2024.pdf)。如果前端没开启目录上传模式,这个属性根本不会存在,后端自然拿不到。
步骤1:前端开启目录上传并传递webkitRelativePath
在HTML的文件上传控件中添加webkitdirectory属性(Chrome、Edge等webkit内核浏览器支持,Firefox也兼容),这样用户就能选择整个目录上传,每个文件都会带上webkitRelativePath:
<input type="file" id="folderUpload" webkitdirectory multiple>
然后在JavaScript中处理上传时,要确保把webkitRelativePath作为额外字段传给后端:
const input = document.getElementById('folderUpload'); input.addEventListener('change', async (e) => { const formData = new FormData(); Array.from(e.target.files).forEach(file => { // 将文件和对应的相对路径一起加入FormData formData.append('files', file); formData.append(`${file.name}_relativePath`, file.webkitRelativePath); }); // 发送请求到后端 await fetch('/upload', { method: 'POST', body: formData }); });
步骤2:后端配置express-fileupload以接收完整信息
如果你用的是express-fileupload模块,默认配置就能解析到文件的基础信息,但需要确保你没有修改过会丢弃额外字段的配置。检查并配置你的Express服务:
const express = require('express'); const fileUpload = require('express-fileupload'); const path = require('path'); const fs = require('fs').promises; const app = express(); // 使用默认配置即可,preserveFilename保持默认true以保留原始文件名 app.use(fileUpload({ preserveFilename: true })); app.post('/upload', async (req, res) => { if (!req.files || Object.keys(req.files).length === 0) { return res.status(400).send('No files were uploaded.'); } // 统一处理单个/多个文件的情况 const fileList = Array.isArray(req.files.files) ? req.files.files : [req.files.files]; try { for (const file of fileList) { // 获取前端传递的相对路径 const relativePath = req.body[`${file.name}_relativePath`]; if (!relativePath) { console.log(`Skipping file ${file.name}: no relative path provided`); continue; } // 解析目标目录并递归创建 const targetDir = path.join(__dirname, 'uploads', path.dirname(relativePath)); await fs.mkdir(targetDir, { recursive: true }); // 保存文件到对应路径 const targetFilePath = path.join(targetDir, path.basename(relativePath)); await file.mv(targetFilePath); console.log(`File saved successfully: ${targetFilePath}`); } res.send('All files uploaded and directory structure created!'); } catch (err) { console.error('Error processing upload:', err); res.status(500).send('Failed to process upload'); } }); app.listen(3000, () => { console.log('Server running on port 3000'); });
特殊场景说明:无法使用目录上传的情况
如果你的业务场景不允许用户上传整个目录,而是需要用户手动选择多个文件并保留原始路径,那这种情况下浏览器是无法提供路径信息的——这是浏览器的安全限制,没有办法绕过。这种时候你只能让用户手动输入路径信息,或者引导用户上传压缩包,后端解压后获取目录结构。
总结一下:核心就是先让前端通过目录上传模式获取到webkitRelativePath,再把这个信息传递给后端,最后用Node.js的fs和path模块来创建对应的文件夹结构。
内容的提问来源于stack exchange,提问作者Stepan Rafael

