Node.js使用Formidable上传docx文件存储路径配置问题
docx文件上传至Node.js服务器存储问题修复方案
实现目标
基于Chrome浏览器、Node.js + HTML + JavaScript技术栈,实现客户端向部署在EC2的Node.js Web服务器上传.docx格式文件,上传后文件存储到服务器指定目录。
现有实现代码
前端HTML片段
<body bgcolor=d9d9d9> <form action="https://kvyfcz.sse.codesandbox.io/upload" method="POST" id=form1 enctype="multipart/form-data"> <h3>Please load the Doc File</h3> <b>Step 1 <input type="file" id=docxFile accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" name="filetoupload" /> <input type="submit" /> <!-- <button type="submit" form="form1" value="Submit">Upload</button> --> </form>
服务端Node.js代码
http .createServer(function (req, res) { if (req.url === "/upload") { res.write("<h1>Dirname is {" + __dirname + "}<br>"); var form = new formidable.IncomingForm(); form.parse(req, function (err, fields, file) { var oldpath = file.filetoupload.filepath; var newpath = __dirname + file.filetoupload.originalFilename; fs.rename(oldpath, newpath, function (error) { if (error) res.write("Rename Error occurred!!"); var output1 = "oldpath is {" + oldpath + "} & newpath is {" + newpath + "} & Dirname is {" + __dirname + "}"; res.write(output1); fs.readFile(newpath, "utf-8", function (err, data) { if (err) res.write("FS Error occurred!!"); else { res.write(data); } }); }); });
当前运行输出
Dirname is {/sandbox} oldpath is {/tmp/83f13a67b2e8a684fd4ddbd01} & newpath is {/sandboxIronman - TestMe.docx} & Dirname is {/sandbox}PK!K���l[Content_Types].xml �(�̗
问题根因
当前Formidable可正常解析上传文件,重命名操作无报错,但存在核心问题:
- 文件未存入预期目录:Formidable默认将上传的临时文件存放在系统临时目录(Linux环境下为
/tmp),由于路径拼接错误,fs.rename实际将文件移动到了系统根目录下名为sandboxIronman - TestMe.docx的位置,而非Node.js进程运行的/sandbox目录,因此在预期目录找不到文件。 - 路径拼接逻辑错误:直接字符串拼接
__dirname和文件名时,缺少Linux系统路径分隔符/,导致生成的路径不符合预期;如果直接用原始文件名作为目标路径,Node.js会以进程启动时的工作目录(process.cwd())为基准寻址,和js文件所在目录(__dirname)不一定一致,极易触发路径不存在或权限报错。 - 额外现象说明:
.docx本质是zip格式的二进制压缩包,用utf-8编码读取后直接返回给前端必然出现乱码,即输出中PK!开头的乱码内容,属于正常现象,不是文件损坏。
修复方案
- 使用Node.js内置path模块拼接路径:调用
path.join()方法拼接路径,该方法会自动适配操作系统的路径分隔符,从根源避免漏写分隔符的问题。 - 指定明确的绝对存储路径:如果需要将文件存在js文件所在目录,用
__dirname作为路径前缀;如果需要存在Node.js进程启动的工作目录,用process.cwd()作为前缀。建议单独创建upload目录作为固定存储位置,提前判断目录是否存在,不存在则自动创建。 - 移除用
utf-8读取docx文件返回的逻辑,避免无意义的乱码输出。
修复后的服务端代码
const http = require('http'); const fs = require('fs'); const path = require('path'); const formidable = require('formidable'); // 配置文件存储目录,此处示例为js文件同目录下的upload文件夹,可自行替换为EC2上的目标绝对路径 const UPLOAD_DIR = path.join(__dirname, 'upload'); // 启动时检查存储目录,不存在则递归创建 if (!fs.existsSync(UPLOAD_DIR)) { fs.mkdirSync(UPLOAD_DIR, { recursive: true }); } http.createServer(function (req, res) { // 仅处理POST方法的/upload请求 if (req.url === "/upload" && req.method.toLowerCase() === 'post') { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); const form = new formidable.IncomingForm(); form.parse(req, function (err, fields, files) { if (err) { res.write("文件解析失败"); res.end(); return; } const uploadFile = files.filetoupload; const tempPath = uploadFile.filepath; // 正确拼接目标存储路径 const targetPath = path.join(UPLOAD_DIR, uploadFile.originalFilename); fs.rename(tempPath, targetPath, function (renameErr) { if (renameErr) { res.write("文件存储失败:" + renameErr.message); res.end(); return; } res.write("<h1>文件上传成功</h1>"); res.write(`<p>临时文件路径:${tempPath}</p>`); res.write(`<p>文件最终存储路径:${targetPath}</p>`); res.end(); }); }); } }).listen(3000, () => { console.log('服务已启动,监听3000端口'); });
部署注意事项
- 部署到EC2时,需要确保Node.js进程对配置的存储目录有写入权限,避免触发权限报错。
- 提前配置EC2安全组,开放服务监听端口的入站规则,前端form的
action属性需要替换为EC2的公网IP+对应端口。 - 生产环境建议对上传文件做后缀、MIME类型校验,同时对文件重命名避免同名文件覆盖,防止恶意文件上传。
内容的提问来源于stack exchange,提问作者Aargee
相关产品推荐
相关产品推荐

