Node.js删除目录旧文件、生成PHP文件打包下载功能异常问题咨询
Node.js批量生成PHP文件并打包下载的时序问题修复方案
问题核心原因
你遇到的问题本质是异步IO操作的时序错误,主要有以下几个错误点:
- 调用
generatePHPFiles和createZipFile两个异步函数时未加await,导致操作未完成就提前执行下载逻辑 - 封装的Promise未等待所有fs异步写入操作完成就提前resolve,实际文件还没写入磁盘
- 压缩包生成逻辑错误,每添加一个文件就写一次压缩包,应该全部添加完成后再统一生成
- 关键词空格替换仅替换了第一个空格,多空格关键词会生成异常文件名
- 原代码漏引入express依赖,且全局挂载了业务中间件,所有请求都会触发文件删除逻辑
修复方案
优化思路
- 替换回调式fs API为Node.js官方自带的Promise版本fs,无需手动封装Promise降低出错概率
- 所有异步操作加
await等待执行完成后再进入下一步 - 修正压缩包生成逻辑,全部文件添加完成后再统一输出压缩包
- 修正空格替换逻辑为全局正则替换,适配多空格关键词场景
- 将业务中间件绑定到指定路由,避免误触发逻辑
修复后完整代码
const fs = require("fs/promises"); const path = require("path"); const axios = require("axios"); const cheerio = require("cheerio"); const zipadm = require("adm-zip"); const express = require('express'); // 初始化应用 const app = express(); // 解析表单参数 app.use(express.urlencoded({ extended: false })) // 配置端口 const PORT = 8000; // 工具函数 async function deletePreviousFiles() { const files = await fs.readdir(__dirname); for (const file of files) { if (file.includes(".php") || file.includes("sitemap.txt") || file.includes(".zip")) { await fs.unlink(path.join(__dirname, file)); } } } async function generateSitemapFile(webpage, words) { const keywords = words.split(","); let sitemapContent = ''; for (let i = 0; i < keywords.length; i++) { let fileName = keywords[i].trim().replace(/\s+/g, "_"); let newLink = `${webpage}${fileName}.php`; sitemapContent += `${newLink}\n`; } await fs.writeFile(`sitemap.txt`, sitemapContent); } async function generatePHPFiles(data, words) { const $ = data; const htmlContent = $.html(); const keywords = words.split(","); const writeTasks = keywords.map(keyword => { let fileName = keyword.trim().replace(/\s+/g, "_"); return fs.writeFile(`${fileName}.php`, htmlContent); }) await Promise.all(writeTasks); } async function createZipFile() { const zip = new zipadm(); const files = await fs.readdir(__dirname); for (const file of files) { if (file.includes(".php") || file.includes("sitemap.txt")) { zip.addLocalFile(path.join(__dirname, file)); } } zip.writeZip(path.join(__dirname, "NewPhpFiles.zip")); } // 业务逻辑中间件 const startApplication = async (req, res, next) => { try { const webPageLink = req.body.link; const seoKeywords = req.body.keywords; await deletePreviousFiles(); console.log("旧文件已删除..."); await generateSitemapFile(webPageLink, seoKeywords); console.log("站点地图已生成..."); let response = await axios.get(webPageLink); const data = cheerio.load(response.data); console.log("网页内容已加载...") await generatePHPFiles(data, seoKeywords); console.log("PHP文件已生成...") await createZipFile(); console.log("压缩包已生成...") next(); } catch (error) { console.log(error) res.status(500).send('服务处理出错,请重试') } } // 下载逻辑 const downloadFile = async (req,res) => { try { res.download(path.join(__dirname, "NewPhpFiles.zip"), (err) => { if(err) { res.status(500).send('文件下载失败') } }); } catch (error) { console.log(error) res.status(500).send('文件下载失败') } } // 路由绑定 app.post("/submit", startApplication, downloadFile) // 启动服务 app.listen(PORT, console.log(`应用已启动,监听端口:${PORT}...`));
内容的提问来源于stack exchange,提问作者Hamza Imranist
相关产品推荐
相关产品推荐

