如何在Fastify路由中全局复用Puppeteer Browser实例?
解决方案
完全可以在服务启动时初始化Puppeteer Browser实例,供所有路由复用——这是避免内存泄漏、提升服务性能的标准做法。
修改后的代码实现
import puppeteer from 'puppeteer' let browser; // 全局存储Browser实例 // Route 1 # Google fastify.get('/google', async (request, reply) => { if (!browser) { reply.code(500).send('Browser instance not initialized'); return; } const page = await browser.newPage(); try { await page.goto('https://google.com', { waitUntil: 'networkidle2' }); const data = await page.evaluate(() => { const body = document.querySelector('body').textContent; return { body }; }); reply.send(data); } catch (err) { reply.code(500).send(err.message); } finally { await page.close(); // 必须关闭页面,释放资源 } }); // Router 2 # Bing fastify.get('/bing', async (request, reply) => { if (!browser) { reply.code(500).send('Browser instance not initialized'); return; } const page = await browser.newPage(); try { await page.goto('https://bing.com', { waitUntil: 'networkidle2' }); const data = await page.evaluate(() => { const body = document.querySelector('body').textContent; return { body }; }); reply.send(data); } catch (err) { reply.code(500).send(err.message); } finally { await page.close(); // 必须关闭页面,释放资源 } }); // Run the server! const start = async () => { try { // 服务启动前初始化Browser实例 browser = await puppeteer.launch({ headless: 'new', // 推荐使用新版无头模式 args: [ '--no-sandbox', '--disable-dev-shm-usage', // 解决容器环境内存不足问题 '--disable-gpu' ], }); await fastify.listen({ port: 3000 }); console.log('🚀 Fastify Server Listening on Port 3000'); // 监听服务关闭事件,清理Browser实例 process.on('SIGINT', async () => { await browser.close(); process.exit(0); }); } catch (err) { fastify.log.error(err); // 如果初始化失败,关闭已创建的Browser(如果有的话) if (browser) await browser.close(); process.exit(1); } }; start();
关键优化点
- 单Browser实例复用:服务启动时只初始化一次Browser,所有路由共享该实例,彻底避免重复启动浏览器带来的资源浪费与内存泄漏风险
- 页面及时回收:每个请求完成后在
finally块中强制关闭页面,防止未关闭的页面累积占用内存 - 服务退出清理:监听进程退出信号,主动关闭Browser实例,避免残留后台进程
- 启动参数优化:添加
--disable-dev-shm-usage解决容器环境下的内存限制问题,使用新版无头模式提升运行稳定性
内容的提问来源于stack exchange,提问作者ton1
相关产品推荐
相关产品推荐

