Express-Zip集成Node.js批量下载Instagram媒体失败求助
解决express-zip与Instagram媒体多文件打包下载问题
问题根源分析
- 全局变量污染:
arrayDocs是全局变量,多次请求会导致旧的文件列表被重复添加,最终压缩包内容混乱。 - express-zip不支持远程URL:
express-zip的path参数仅支持本地文件路径,直接传入Instagram的远程URL无法读取内容,导致生成空压缩包(66字节)。 - 异步逻辑处理不当:循环中直接调用
res.zip,但未等待所有远程文件下载完成,服务器可能提前响应或卡住。
修正后的代码
const express = require("express"); const request = require("request").defaults({ encoding: null }); // 配置默认返回Buffer const bodyParser = require("body-parser"); const instaAPI = require("igdown-scrapper"); const app = express(); const port = 3000; const zip = require("express-zip"); app.use(bodyParser.urlencoded({ extended: false })); app.set("view engine", "ejs"); app.get("/", (req, res) => { res.render("index"); }); app.post("/download", async (req, res) => { const url = req.body.url; if (!url || !url.startsWith("https://www.instagram.com/")) { return res.render("index", { error: "Invalid URL" }); } try { const data = await instaAPI(url); // 处理多文件情况 if (Array.isArray(data) && data.length > 1) { const zipFiles = []; // 并行下载所有媒体文件 await Promise.all(data.map(async (item, index) => { const mediaUrl = item.url[0].url; const ext = item.url[0].ext; const fileName = `${Date.now()}-${index}.${ext}`; // 下载远程文件到Buffer const fileBuffer = await new Promise((resolve, reject) => { request.get(mediaUrl, (err, response, body) => { if (err || response.statusCode !== 200) { return reject(new Error(`Failed to download ${mediaUrl}`)); } resolve(body); }); }); // 添加到压缩包列表(使用data参数传递Buffer) zipFiles.push({ data: fileBuffer, name: fileName }); })); // 生成并发送压缩包 res.zip(zipFiles); } else { // 单文件下载逻辑 const mediaUrl = data.url[0].url; const ext = data.url[0].ext; const fileName = `${Date.now()}.${ext}`; request.get(mediaUrl, (err, response, body) => { if (err || response.statusCode !== 200) { return res.status(400).send("Error downloading media"); } res.setHeader("Content-Type", "application/octet-stream"); res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`); res.send(body); }); } } catch (err) { console.error(err); res.render("index", { error: "Failed to fetch Instagram media" }); } }); app.listen(port, () => { console.log("App is listening on port 3000"); });
关键改进点
- 局部变量替代全局变量:将
arrayDocs改为请求内的zipFiles,避免跨请求数据污染。 - 支持远程文件压缩:通过
request下载远程文件到Buffer,使用express-zip的data参数传递文件内容,而非无效的远程URL。 - 异步并行处理:用
Promise.all并行下载所有媒体文件,确保所有文件准备完成后再生成压缩包,避免服务器卡住或提前响应。 - 错误捕获:添加
try/catch捕获API请求和文件下载中的错误,提升稳定性。
内容的提问来源于stack exchange,提问作者tionxs
相关产品推荐
相关产品推荐

