You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地正常的Puppeteer部署Vercel报错,求解决或替代方案

解决Vercel部署下页面资源总传输量统计问题(替代Puppeteer方案)

一、核心需求明确

你需要统计页面及所有关联资源的总传输量,当前使用Puppeteer在Vercel部署时遇到Chrome版本匹配问题,以下是可行的替代方案及优化建议:

二、替代方案推荐

1. Playwright(推荐,精度与Puppeteer一致)

Playwright是微软维护的自动化工具,对Vercel这类Serverless环境兼容性更好,无需手动配置Chromium路径,会自动适配运行环境。

实现步骤:

  • 安装依赖:
npm install playwright
  • 替换统计函数代码:
import { chromium } from 'playwright';

async function calculateTotalDataTransferWithResources(url) {
  let browser;
  try {
    // Vercel环境下自动适配Chromium
    browser = await chromium.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox']
    });
    const page = await browser.newPage();
    
    // 等待页面完全加载(包括所有资源)
    await page.goto(url, { waitUntil: 'networkidle0' });
    
    // 复用Puppeteer的performance API逻辑获取资源数据
    const networkData = await page.evaluate(() => {
      return window.performance.getEntriesByType('resource').map(resource => ({
        name: resource.name,
        transferSize: resource.transferSize
      }));
    });
    
    const totalData = networkData.reduce((total, resource) => total + resource.transferSize, 0);
    
    return { totalData, networkData };
  } catch (error) {
    console.error('统计错误:', error.message);
    return { totalData: 0, networkData: [] };
  } finally {
    if (browser) await browser.close();
  }
}
  • Vercel部署说明:Playwright会在postinstall阶段自动下载对应版本的Chromium,无需额外配置脚本,直接部署即可。

2. 纯Node.js网络请求方案(轻量,无浏览器依赖)

如果目标页面以静态资源为主,无需统计JS动态加载的资源,可以用axios+cheerio模拟资源加载流程,计算总传输量。

实现步骤:

  • 安装依赖:
npm install axios cheerio
  • 统计函数代码:
import axios from 'axios';
import cheerio from 'cheerio';
import { URL } from 'url';

async function calculateTotalDataTransfer(url) {
  let totalSize = 0;
  const visitedUrls = new Set();

  // 递归请求资源并统计大小
  async function fetchResource(resourceUrl) {
    if (visitedUrls.has(resourceUrl)) return;
    visitedUrls.add(resourceUrl);

    try {
      const response = await axios.get(resourceUrl, {
        responseType: 'stream',
        validateStatus: () => true // 忽略错误状态码,继续统计
      });
      
      // 优先用Content-Length,否则通过流计算大小
      const contentLength = response.headers['content-length'];
      if (contentLength) {
        totalSize += parseInt(contentLength, 10);
      } else {
        let size = 0;
        for await (const chunk of response.data) {
          size += chunk.length;
        }
        totalSize += size;
      }

      // 解析HTML页面,提取内嵌资源
      const contentType = response.headers['content-type'];
      if (contentType && contentType.includes('text/html')) {
        const html = await axios.get(resourceUrl);
        const $ = cheerio.load(html.data);
        const baseUrl = new URL(resourceUrl);

        // 提取脚本、样式、图片等资源URL
        const resources = [
          ...$('script[src]').map((_, el) => $(el).attr('src')).get(),
          ...$('link[rel="stylesheet"]').map((_, el) => $(el).attr('href')).get(),
          ...$('img[src]').map((_, el) => $(el).attr('src')).get(),
          ...$('link[rel="preload"]').map((_, el) => $(el).attr('href')).get()
        ].filter(Boolean);

        // 转换为绝对URL并并行请求
        const absoluteResources = resources.map(src => {
          try {
            return new URL(src, baseUrl).href;
          } catch {
            return null;
          }
        }).filter(Boolean);

        await Promise.all(absoluteResources.map(fetchResource));
      }
    } catch (error) {
      console.error('资源请求失败:', resourceUrl, error.message);
    }
  }

  await fetchResource(url);
  return { 
    totalData: totalSize, 
    networkData: Array.from(visitedUrls).map(url => ({ name: url })) 
  };
}
  • 局限性:无法统计JS动态渲染加载的资源(如点击事件触发的请求),仅适合静态页面场景。

3. Edge Functions + Undici(极致轻量,适配Vercel Edge环境)

如果使用Next.js Edge API Routes,可采用undici做HTTP请求,结合HTML解析,适合Edge环境的低延迟需求。

代码示例(Edge API Route):

import { fetch } from 'undici';
import { parse } from 'node-html-parser';
import { URL } from 'url';

export const config = {
  runtime: 'edge',
};

export default async function handler(req) {
  const { url } = await req.json();
  let totalSize = 0;
  const visitedUrls = new Set();

  async function fetchResource(resourceUrl) {
    if (visitedUrls.has(resourceUrl)) return;
    visitedUrls.add(resourceUrl);

    try {
      const response = await fetch(resourceUrl);
      
      // 统计资源大小
      const contentLength = response.headers.get('content-length');
      if (contentLength) {
        totalSize += parseInt(contentLength, 10);
      } else {
        const buffer = await response.arrayBuffer();
        totalSize += buffer.byteLength;
      }

      // 解析HTML资源
      const contentType = response.headers.get('content-type');
      if (contentType && contentType.includes('text/html')) {
        const html = await response.text();
        const root = parse(html);
        const baseUrl = new URL(resourceUrl);

        const resources = [
          ...root.querySelectorAll('script[src]').map(el => el.getAttribute('src')),
          ...root.querySelectorAll('link[rel="stylesheet"]').map(el => el.getAttribute('href')),
          ...root.querySelectorAll('img[src]').map(el => el.getAttribute('src')),
          ...root.querySelectorAll('link[rel="preload"]').map(el => el.getAttribute('href'))
        ].filter(Boolean);

        const absoluteResources = resources.map(src => {
          try {
            return new URL(src, baseUrl).href;
          } catch {
            return null;
          }
        }).filter(Boolean);

        await Promise.all(absoluteResources.map(fetchResource));
      }
    } catch (error) {
      console.error('资源请求失败:', resourceUrl, error.message);
    }
  }

  await fetchResource(url);
  return new Response(JSON.stringify({ 
    totalData: totalSize, 
    networkData: Array.from(visitedUrls) 
  }), {
    headers: { 'Content-Type': 'application/json' },
  });
}

三、方案选择建议

  • 需要精确统计所有资源(包括动态加载):选Playwright,兼容性和精度与Puppeteer一致,Vercel部署无额外配置。
  • 静态页面场景,追求轻量:选纯Node.js网络请求方案,无浏览器依赖,部署成本更低。
  • 低延迟需求,适配Edge环境:选Edge Functions方案,响应更快,适合高并发场景。

内容的提问来源于stack exchange,提问作者Info Applikation

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 10:44:53