Web应用迁移:fs.readdirSync与fs.writeFileSync替代方案咨询
Electron转Web服务端应用fs同步操作替代方案
核心前提
浏览器端受安全沙箱限制,无法直接静默操作用户本地文件系统,所有文件读写逻辑必须拆分到服务端实现,前端仅负责发起接口请求、接收返回结果,无任何绕过该限制的方案。
方案1:Node.js服务端实现(最小迁移成本)
如果你的服务端采用Node.js技术栈(Express/Koa/Nest等),原生fs模块可直接使用,无需额外引入第三方依赖,仅需注意:服务端生产环境不推荐使用同步IO方法,高并发场景下同步方法会阻塞Node.js事件循环,导致所有请求响应卡顿。
临时过渡兼容写法(仅适合低并发内部工具)
可直接沿用原有同步逻辑,仅需将路径拼接替换为跨平台安全的path.resolve写法,同时增加路径合法性校验,避免路径遍历漏洞。对应原有业务逻辑的代码示例:
const fs = require('node:fs'); const path = require('node:path'); // 读取指定目录下所有子文件夹名称 function getLayers(invoicesBasePath) { const targetPath = path.resolve(invoicesBasePath); return fs.readdirSync(targetPath, { withFileTypes: true }) .filter(entry => entry.isDirectory()) .map(entry => entry.name); } // 读取指定目录下所有图片格式文件名称 function getImageItemNames(invoicesBasePath, invoicesName, itemFolderName) { const targetPath = path.resolve(invoicesBasePath, invoicesName, itemFolderName); const imgSuffixReg = /.*(gif|jpe?g|tiff?|png|webp|bmp)$/i; return fs.readdirSync(targetPath, { withFileTypes: true }) .filter(entry => !entry.isDirectory()) .filter(entry => imgSuffixReg.test(entry.name)) .map(entry => entry.name); } // 写入JSON文件 function writeJsonFile(targetDir, fileName, data) { const targetPath = path.resolve(targetDir, fileName); fs.writeFileSync(targetPath, JSON.stringify(data), { encoding: 'utf8' }); }
注意:必须对传入接口的路径参数做白名单校验,禁止传入
../等跨路径字符,防止攻击者恶意读写服务器敏感文件。
生产环境推荐异步写法
替换为Node.js原生fs/promises异步API,配合async/await写法,代码结构和同步逻辑基本一致,且不会阻塞事件循环:
const fs = require('node:fs/promises'); const path = require('node:path'); async function getLayers(invoicesBasePath) { const targetPath = path.resolve(invoicesBasePath); const entries = await fs.readdir(targetPath, { withFileTypes: true }); return entries.filter(entry => entry.isDirectory()).map(entry => entry.name); } async function getImageItemNames(invoicesBasePath, invoicesName, itemFolderName) { const targetPath = path.resolve(invoicesBasePath, invoicesName, itemFolderName); const imgSuffixReg = /.*(gif|jpe?g|tiff?|png|webp|bmp)$/i; const entries = await fs.readdir(targetPath, { withFileTypes: true }); return entries .filter(entry => !entry.isDirectory()) .filter(entry => imgSuffixReg.test(entry.name)) .map(entry => entry.name); } async function writeJsonFile(targetDir, fileName, data) { const targetPath = path.resolve(targetDir, fileName); await fs.writeFile(targetPath, JSON.stringify(data), { encoding: 'utf8' }); }
前端侧仅需封装对应HTTP接口,比如获取目录列表调用GET /api/layers、写入文件调用POST /api/save-file,将参数传递给服务端,由服务端完成实际文件操作后返回结果即可。
方案2:非Node.js服务端实现
如果服务端采用Java/Python/Go等其他技术栈,无需强行复刻Node.js的fs方法,直接使用对应语言标准库的文件IO能力实现业务逻辑即可:
- 读目录逻辑:调用标准库遍历指定路径的接口,过滤出目录/符合图片后缀的文件,返回名称列表
- 写文件逻辑:接收前端传递的存储路径、文件名、待写入数据,序列化后写入服务端存储路径
所有实现同样需要做路径合法性校验,封堵路径遍历漏洞。
特殊场景:需要操作访问者本地文件
如果业务需求是Web应用操作用户本地的文件,无法通过静默方式实现,必须由用户主动触发授权:
- 读文件/目录:使用现代浏览器支持的File System Access API,由用户主动选择授权的目录/文件后,才能拿到句柄读取内容,该API需要HTTPS环境,支持Chrome/Edge等Chromium内核浏览器
- 写文件:可通过File System Access API获得用户授权后写入,或通过传统的下载触发方式,将文件保存到用户指定的下载目录
内容的提问来源于stack exchange,提问作者AmoxiciTeo
相关产品推荐
相关产品推荐

