部署至Heroku后fs.readdir访问本地路径报错的问题咨询
本地正常但部署到Heroku后出现ENOENT路径错误的解决方法
问题描述
本地开发时,使用Node.js的fs.readdir()访问Windows本地绝对路径,调用localhost:4000/api/readExcelFile接口运行正常;但将项目部署到Heroku后,调用线上接口https://word-word-number.herokuapp.com/api/readExcelFile时,抛出ENOENT错误:
[Error: ENOENT: no such file or directory, scandir 'C:\Users\Kiko Pindoy\Desktop\Island Gas\files\unprocessed'] { errno: -2, code: 'ENOENT', syscall: 'scandir', path: 'C:\\Users\\Kiko Pindoy\\Desktop\\Island Gas\\files\\unprocessed'}
相关代码:
module.exports.validateFolder = async () => { fs.readdir('C:\\Users\\Kiko Pindoy\\Desktop\\Island Gas\\files\\unprocessed', (error, files) => { if(error) { throw error } else { if(files.length < 1) { let logsPath = 'C:\\Users\\Kiko Pindoy\\Desktop\\Island Gas\\files\\logs\\error' let processDate = new Date().toISOString().slice(0, 10) let content = `No Files Found in C:\\Users\\Kiko Pindoy\\Desktop\\Island Gas\\files\\unprocessed\n` fs.appendFile(`${logsPath}\\${processDate}.txt`, content, error => { if(error) { throw error } }) } else { for(let i = 0; i < files.length; i++) { this.validateSheets(`C:\\Users\\Kiko Pindoy\\Desktop\\Island Gas\\files\\unprocessed\\${files[i]}`, files[i]) } } } })}
问题原因
- 硬编码路径不适用于云端环境:Heroku服务器基于Linux系统,没有Windows的C盘用户目录结构,且无法访问你本地电脑的文件系统。
- 异步代码逻辑缺陷:
async函数内使用回调版fs方法,回调中的throw error无法被外部捕获,错误处理不完整。 - 未考虑Heroku文件系统特性:Heroku的本地文件系统是临时存储,服务器重启后所有文件会丢失,不适合持久化业务文件。
解决步骤
1. 替换硬编码路径,使用项目相对路径
放弃Windows本地绝对路径,改用项目内的相对路径,结合path模块处理跨系统路径分隔符:
const path = require('path'); // 项目内的未处理文件目录 const unprocessedDir = path.join(__dirname, 'files', 'unprocessed'); // 项目内的错误日志目录 const logsDir = path.join(__dirname, 'files', 'logs', 'error');
2. 确保目录存在
在读取/写入文件前,先递归创建所需目录,避免因目录不存在报错:
const fs = require('fs').promises; // recursive: true 会自动创建多级目录 await fs.mkdir(unprocessedDir, { recursive: true }); await fs.mkdir(logsDir, { recursive: true });
3. 修正异步代码逻辑
改用Promise版fs方法配合async/await,确保错误能被正确捕获和处理:
const fs = require('fs').promises; const path = require('path'); module.exports.validateFolder = async () => { const unprocessedDir = path.join(__dirname, 'files', 'unprocessed'); const logsDir = path.join(__dirname, 'files', 'logs', 'error'); // 预创建目录 await fs.mkdir(unprocessedDir, { recursive: true }); await fs.mkdir(logsDir, { recursive: true }); try { const files = await fs.readdir(unprocessedDir); if (files.length === 0) { const processDate = new Date().toISOString().slice(0, 10); const logFilePath = path.join(logsDir, `${processDate}.txt`); const content = `No Files Found in ${unprocessedDir}\n`; await fs.appendFile(logFilePath, content); } else { for (const fileName of files) { const filePath = path.join(unprocessedDir, fileName); // 若validateSheets是异步方法,需用await等待执行完成 await this.validateSheets(filePath, fileName); } } } catch (err) { console.error('处理文件目录失败:', err); throw err; // 按需向上抛出错误或自行处理 } };
4. 处理文件持久化问题
Heroku本地文件系统是临时的,若需要长期存储文件,建议使用云存储服务(如AWS S3):
- 实现文件上传接口,将客户端的Excel文件上传到云存储
- 读取文件时直接从云存储获取,而非依赖服务器本地文件系统
5. 配置Heroku环境变量(可选)
如果需要动态配置文件路径,可在Heroku后台设置环境变量,代码中通过process.env读取:
// 优先读取环境变量,默认使用项目内路径 const unprocessedDir = process.env.FILES_UNPROCESSED_DIR || path.join(__dirname, 'files', 'unprocessed');
内容的提问来源于stack exchange,提问作者Kiko
相关产品推荐
相关产品推荐

