Puppeteer部署至Vercel(Next.js)出现性能与504超时问题求助
问题分析与修复方案
你的代码核心问题在于资源未彻底释放和缺少超时控制,这也是本地运行正常但生产环境(Vercel)出现内存过高、504超时的根本原因:
核心问题点
- 未关闭
browser实例:每次请求仅关闭页面,浏览器进程残留,多次请求后引发内存泄漏,最终触发内存溢出或超时。 - 页面加载无超时限制:生产环境网络不稳定时,默认加载超时(30秒)会超过Vercel的请求阈值,直接返回504。
- 错误分支未清理资源:请求出错时浏览器进程未关闭,进一步加剧内存占用问题。
- 生产环境Chrome启动参数未做针对性优化,内存消耗过大。
修复后的完整代码
const chrome = require("chrome-aws-lambda"); export default async function handler(req, res) { let browser = null; try { browser = await chrome.puppeteer.launch({ args: [ ...chrome.args, "--disable-gpu", "--disable-dev-shm-usage", "--disable-setuid-sandbox", "--no-sandbox", "--single-process", // 单进程模式降低内存占用 ], executablePath: process.env.NODE_ENV === "production" ? await chrome.executablePath : undefined, headless: "new", // 新版无头模式,更轻量高效 timeout: 10000, // 浏览器启动超时10秒 }); const page = await browser.newPage(); // 清理多余的空白页面 const blankPages = await browser.pages(); for (const blankPage of blankPages.slice(1)) { await blankPage.close(); } // 控制页面加载超时,仅等待DOM加载完成 await page.goto("https://mars.nasa.gov/msl/weather/", { waitUntil: "domcontentloaded", timeout: 10000, // 页面加载超时10秒 }); const nasaWeatherDataScrape = await page.evaluate(() => { const high = Array.from(document.querySelectorAll(".celsius .high")).map(x => x.innerText); const low = Array.from(document.querySelectorAll(".celsius .low")).map(x => x.innerText); return { high, low }; }); // 添加缓存策略,减少重复爬取 res.setHeader('Cache-Control', 's-maxage=300, stale-while-revalidate=600'); res.json(nasaWeatherDataScrape); } catch (error) { console.error(error); res.status(500).json({ message: error.message }); } finally { // 无论成功失败,强制关闭浏览器释放资源 if (browser) { await browser.close(); } } }
关键优化说明
- 强制释放浏览器资源:用
finally块确保请求结束后关闭browser,彻底清理进程,避免内存泄漏。 - 严格超时控制:给浏览器启动、页面加载都设置10秒超时,适配Vercel的请求时间限制。
- 轻量启动配置:启用新版无头模式、单进程模式,添加内存优化参数,降低生产环境资源消耗。
- 缓存优化:添加
Cache-Control头,将爬取结果缓存5分钟,减少重复启动浏览器的次数,大幅提升性能。
内容的提问来源于stack exchange,提问作者Seamus O'Sullivan
相关产品推荐
相关产品推荐

