修复: 优化文件上传临时文件清理机制

问题描述:
- 文件删除操作可能抛出异常导致程序中断
- 服务器崩溃或重启后残留临时文件无法清理
- 没有自动清理机制

修复内容:
1. 添加safeDeleteFile()安全删除函数
   - 使用try-catch捕获删除异常
   - 记录删除日志和错误信息
   - 不会因删除失败而中断主流程

2. 添加cleanupOldTempFiles()定期清理函数
   - 启动时自动清理超过24小时的临时文件
   - 防止临时文件堆积占用磁盘空间
   - 容错处理避免清理失败影响启动

3. 替换所有fs.unlinkSync为safeDeleteFile
   - 文件大小超限时的临时文件清理
   - 上传成功后的临时文件清理
   - 上传失败时的临时文件清理

影响范围: 文件上传功能

测试建议:
- 上传文件后检查uploads目录临时文件已删除
- 重启服务器验证旧临时文件自动清理
- 模拟删除失败场景验证不影响主流程

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-11 13:46:33 +08:00
parent 3359cb8c01
commit 4a9d31806b

View File

@@ -69,6 +69,54 @@ const shareFileCache = new Map();
// ===== 工具函数 ===== // ===== 工具函数 =====
// 安全删除文件(不抛出异常)
function safeDeleteFile(filePath) {
try {
if (fs.existsSync(filePath)) {
fs.unlinkSync(filePath);
console.log(`[清理] 已删除临时文件: ${filePath}`);
return true;
}
} catch (error) {
console.error(`[清理] 删除临时文件失败: ${filePath}`, error.message);
return false;
}
}
// 清理旧的临时文件(启动时执行一次)
function cleanupOldTempFiles() {
const uploadsDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadsDir)) {
return;
}
try {
const files = fs.readdirSync(uploadsDir);
const now = Date.now();
const maxAge = 24 * 60 * 60 * 1000; // 24小时
let cleaned = 0;
files.forEach(file => {
const filePath = path.join(uploadsDir, file);
try {
const stats = fs.statSync(filePath);
if (now - stats.mtimeMs > maxAge) {
fs.unlinkSync(filePath);
cleaned++;
}
} catch (err) {
console.error(`[清理] 检查文件失败: ${filePath}`, err.message);
}
});
if (cleaned > 0) {
console.log(`[清理] 已清理 ${cleaned} 个超过24小时的临时文件`);
}
} catch (error) {
console.error('[清理] 清理临时文件目录失败:', error.message);
}
}
// SFTP连接 // SFTP连接
async function connectToSFTP(config) { async function connectToSFTP(config) {
const sftp = new SftpClient(); const sftp = new SftpClient();
@@ -696,7 +744,7 @@ app.post('/api/upload', authMiddleware, upload.single('file'), async (req, res)
if (req.file.size > maxUploadSize) { if (req.file.size > maxUploadSize) {
// 删除已上传的临时文件 // 删除已上传的临时文件
if (fs.existsSync(req.file.path)) { if (fs.existsSync(req.file.path)) {
fs.unlinkSync(req.file.path); safeDeleteFile(req.file.path);
} }
return res.status(413).json({ return res.status(413).json({
@@ -725,7 +773,7 @@ app.post('/api/upload', authMiddleware, upload.single('file'), async (req, res)
console.log(`[上传] 文件上传成功: ${remoteFilePath}`); console.log(`[上传] 文件上传成功: ${remoteFilePath}`);
// 删除本地临时文件 // 删除本地临时文件
fs.unlinkSync(req.file.path); safeDeleteFile(req.file.path);
res.json({ res.json({
success: true, success: true,
@@ -738,7 +786,7 @@ app.post('/api/upload', authMiddleware, upload.single('file'), async (req, res)
// 删除临时文件 // 删除临时文件
if (fs.existsSync(req.file.path)) { if (fs.existsSync(req.file.path)) {
fs.unlinkSync(req.file.path); safeDeleteFile(req.file.path);
} }
res.status(500).json({ res.status(500).json({
@@ -2154,6 +2202,9 @@ app.get("/s/:code", (req, res) => {
res.redirect(frontendUrl); res.redirect(frontendUrl);
}); });
// 启动时清理旧临时文件
cleanupOldTempFiles();
// 启动服务器 // 启动服务器
app.listen(PORT, '0.0.0.0', () => { app.listen(PORT, '0.0.0.0', () => {
console.log(`\n========================================`); console.log(`\n========================================`);