Vercel 中使用 puppeteer 获取 网站页面截图 问题 及修复

233 阅读2分钟

Vercel中使用 puppeteer 获取 网站页面截图

由于使用Microlink有次数限制,所以打算自己来获取网站截图,总结很多踩坑的地方

我踩过的坑,希望你不会再次深陷其中

项目地址

在线项目地址

截图服务相关错误 (screen/route.ts)

1. Chromium 启动错误

Failed to launch the browser process!
/tmp/chromium: error while loading shared libraries: libnspr4.so
解决方案
  • 使用兼容的 Chromium 版本
  • 添加必要的启动参数
const options = {
  args: [
    ...chromium.args,
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--disable-dev-shm-usage',
  ],
  executablePath: process.env.NODE_ENV === 'production'
    ? await chromium.executablePath()
    : '本地Chrome路径',
  headless: true
};

2. 环境兼容性错误

The input directory "/var/task/.next/server/app/api/bin" does not exist
解决方案
  • 配置 vercel.json
{
  "functions": {
    "app/api/screen/route.ts": {
      "memory": 1024,
      "maxDuration": 60
    }
  }
}

3.npm版本问题 高版本 npm puppeteer 中缺失某个包

package.json

pupp
  "engines": {
    "node": "^18"
  }

网站信息抓取错误 (scrape/route.ts)

1. 数据验证错误

if (!url || !categoryName || !image || !title) {
  return NextResponse.json(
    { error: '缺少必要的信息' }, 
    { status: 400 }
  );
}

2. 重复数据错误

if (sites.some(site => site.url === url)) {
  return NextResponse.json(
    { error: '该网站已经添加过了' }, 
    { status: 400 }
  );
}

截图处理错误 (screenshot/route.ts)

1. 上传超时错误

const MAX_RETRIES = 3;
const RETRY_DELAY = 1000;

async function fetchWithRetry(url: string, retries = MAX_RETRIES) {
  for (let i = 0; i < retries; i++) {
    try {
      // 请求逻辑
    } catch (error) {
      if (i === retries - 1) throw error;
      await sleep(RETRY_DELAY);
    }
  }
}

2. 图片处理错误

try {
  const imageUrl = await uploadToTencentCOS(
    `data:image/jpeg;base64,${screenshot}`,
    filename
  );
} catch (error) {
  console.error('Upload error:', error);
  return NextResponse.json(
    { error: '图片上传失败' },
    { status: 500 }
  );
}

通用错误处理策略

1. 错误响应格式统一

return NextResponse.json(
  { 
    error: error instanceof Error ? error.message : '未知错误',
    code: status,
    timestamp: new Date().toISOString()
  }, 
  { status }
);

2. 错误日志记录

console.error('Error details:', {
  api: 'screen/route.ts',
  error: error instanceof Error ? error.message : error,
  timestamp: new Date().toISOString(),
  url: req.url
});

最佳实践建议

  1. 错误分类

    • 区分业务错误和技术错误
    • 提供清晰的错误信息
    • 使用合适的 HTTP 状态码
  2. 重试机制

    • 对网络请求实现重试
    • 使用指数退避策略
    • 设置最大重试次数
  3. 超时控制

    • 设置合理的超时时间
    • 实现请求取消机制
    • 提供超时提示
  4. 资源清理

    • 确保浏览器实例正确关闭
    • 清理临时文件
    • 释放系统资源
  5. 监控告警

    • 记录关键错误信息
    • 实现错误上报机制
    • 设置错误阈值告警

常见错误码说明

  • 400: 请求参数错误
  • 401: 未授权访问
  • 403: 禁止访问
  • 404: 资源不存在
  • 408: 请求超时
  • 429: 请求过于频繁
  • 500: 服务器内部错误
  • 503: 服务暂时不可用

调试技巧

  1. 使用详细的日志记录
  2. 设置断点调试
  3. 使用错误追踪工具
  4. 模拟各种错误场景
  5. 测试错误恢复机制

注意:这些错误处理策略需要根据具体的业务场景和需求进行调整。

源码地址 github.com/Liboq/super…