项目概述
本项目实现无头截图服务:在无头浏览器中渲染页面并按请求视口返回 PNG,配以超时与隔离,使恶意页面无法挂起服务。两个关键问题是超时与隔离——每一个导航都要有界,每个请求都要有独立上下文。
架构与关键决策
以浏览器实例池服务请求、每请求一个上下文,使并发由池大小而非到达流量决定;导航超时覆盖整页生命周期(含网络空闲),使持续加载永不收敛的页面不能长期占用工作进程。URL 守卫校验协议并解析主机,在浏览器导航前拒绝私有与回环地址,且需在重定向后复查,因为重定向是绕过一次性检查的常见手法。
实施与测试
以两个视口截取本地静态页断言 PNG 尺寸;请求 file 或内网地址断言被守卫拒绝;断言永不收敛的页面超时而非挂起;断言两个请求不共享 cookie,证明上下文确为隔离。
限制与后续
- 仅截取单视口的静态图,不做滚动分页与全页截图。
- 不对目标 URL 鉴权,私有页面需另传会话。
- 不存储截图,缓存与保留交给调用方。
代码示例
pnpm init
pnpm add playwright express
pnpm add -D typescript tsx vitest
screenshot-service/
├── src/pool.ts
├── src/capture.ts
├── src/viewport.ts
├── src/guard.ts
├── tests/screenshot.test.ts
└── package.json
const browser = await chromium.launch();
pool.push(browser);
const ctx = await browser.newContext({ viewport });
await page.goto(url, { timeout: 15000, waitUntil: 'networkidle' });
const buf = await page.screenshot({ fullPage, type: 'png' });
if (!isPublicHttpUrl(url)) throw new Error('blocked url');
pnpm vitest run