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

NextJS 13.4.4部署至Vercel后Puppeteer无法运行求助

问题描述

我在NextJS API路由中用Puppeteer把动态HTML转成PDF,再通过邮件发送。本地开发完全正常,但部署到Vercel后调用API时出现以下错误:

  • info Loaded env from /var/task/.env
  • error Error: Could not find Chrome (ver. 113.0.5672.63). This can occur if either
  1. you did not perform an installation before running the script (e.g. npm install) or
  2. your cache path is incorrectly configured (which is: /home/sbx_user1051/.cache/puppeteer).
    For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
    at ChromeLauncher.resolveExecutablePath (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:300:27)
    at ChromeLauncher.executablePath (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:181:25)
    at ChromeLauncher.computeLaunchArguments (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ChromeLauncher.js:97:37)
    at async ChromeLauncher.launch (/var/task/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:83:28)
    at async POST (/var/task/.next/server/app/api/p2/route.js:201:21)
    at async /var/task/.next/server/chunks/625.js:2905:37

我试过Puppeteer文档里的配置文件,但都没用,我的代码如下:

import { NextResponse } from "next/server";

const puppeteer = require("puppeteer");
import mustache from "mustache";
const fs = require("fs");
const nodemailer = require("nodemailer");

export async function POST(request: Request) {
    const data = {
        nombre: "Vanessa",
        precio: 100,
        acciones: 12,
    };
    const user = await request.json();

    const browser = await puppeteer.launch({
        headless: "new",
        args: ["--no-sandbox"],
        product: "firefox",
    });

    const page = await browser.newPage();

    const html = fs.readFileSync("src/app/api/p2/template.html", "utf8");
    const filledHtml = mustache.render(html, data);
    await page.setContent(filledHtml, { waitUntil: "domcontentloaded" });

    await page.emulateMediaType("screen");

    const pdf = await page.pdf({
        format: "A4",
        printBackground: true,
        margin: {
            top: "20px",
            bottom: "40px",
            left: "20px",
            right: "20px",
        },
        path: "result.pdf",
    });

    await browser.close();
    console.log("Se genero el pdf");

    let transporter = nodemailer.createTransport({
        host: "m40.siteground.biz",
        port: 465,
        secure: true, // upgrade later with STARTTLS
        auth: {
            user: someuser,
            pass: somepass,
        },
    });

    let mailOptions = {
        from: someemail,
        to: someotheremail,
        subject: "Sending Email using Node.js",
        html: "<h1>Welcome</h1><p>That was easy!</p>",
        attachments: [
            {
                filename: "result.pdf",
                path: "result.pdf",
                contentType: "application/pdf",
            },
        ],
    };

    transporter.sendMail(mailOptions, function (error: any, info: any) {
        if (error) {
            console.log(error);
        } else {
            console.log("Email sent: " + info.response);
        }
    });

    return NextResponse.json("Se genero el pdf");
}
解决方案

Vercel的Serverless函数环境没有预装Chrome/Firefox,直接用puppeteer包会因为找不到浏览器二进制文件报错。下面是具体解决步骤:

步骤1:替换依赖

卸载原puppeteer,安装适配Serverless环境的包:

npm uninstall puppeteer
npm install puppeteer-core chrome-aws-lambda

步骤2:修改API代码

调整浏览器启动逻辑,用内存处理PDF避免文件系统限制,同时用环境变量存敏感信息:

import { NextResponse } from "next/server";
import puppeteer from "puppeteer-core";
import mustache from "mustache";
import fs from "fs/promises";
import path from "path";
import nodemailer from "nodemailer";

export async function POST(request: Request) {
    const data = {
        nombre: "Vanessa",
        precio: 100,
        acciones: 12,
    };
    const user = await request.json();

    // 用chrome-aws-lambda获取适配Vercel的浏览器配置
    const chrome = require("chrome-aws-lambda");
    const browser = await puppeteer.launch({
        args: chrome.args,
        executablePath: await chrome.executablePath,
        headless: chrome.headless,
        ignoreHTTPSErrors: true,
    });

    const page = await browser.newPage();

    // 确保模板路径在生产环境正确
    const templatePath = path.resolve(process.cwd(), "src/app/api/p2/template.html");
    const html = await fs.readFile(templatePath, "utf8");
    const filledHtml = mustache.render(html, data);
    
    await page.setContent(filledHtml, { waitUntil: "domcontentloaded" });
    await page.emulateMediaType("screen");

    // 直接生成PDF Buffer,不写入本地文件
    const pdfBuffer = await page.pdf({
        format: "A4",
        printBackground: true,
        margin: {
            top: "20px",
            bottom: "40px",
            left: "20px",
            right: "20px",
        },
    });

    await browser.close();
    console.log("PDF生成成功");

    // 邮件发送逻辑,用Buffer作为附件
    let transporter = nodemailer.createTransport({
        host: "m40.siteground.biz",
        port: 465,
        secure: true,
        auth: {
            user: process.env.EMAIL_USER,
            pass: process.env.EMAIL_PASS,
        },
    });

    let mailOptions = {
        from: process.env.EMAIL_FROM,
        to: process.env.EMAIL_TO,
        subject: "PDF已生成",
        html: "<h1>您好</h1><p>附件是生成的PDF文件</p>",
        attachments: [
            {
                filename: "result.pdf",
                content: pdfBuffer,
                contentType: "application/pdf",
            },
        ],
    };

    try {
        await transporter.sendMail(mailOptions);
        console.log("邮件发送成功");
        return NextResponse.json({ message: "PDF生成并发送成功" });
    } catch (error) {
        console.error("邮件发送失败", error);
        return NextResponse.json({ error: "操作失败" }, { status: 500 });
    }
}

步骤3:配置环境变量

在Vercel控制台添加以下环境变量:

  • EMAIL_USER: 邮箱账号
  • EMAIL_PASS: 邮箱授权码/密码
  • EMAIL_FROM: 发件人邮箱
  • EMAIL_TO: 收件人邮箱

关键说明

  1. chrome-aws-lambda:自动适配Vercel环境,提供预编译的Chrome二进制文件,不用手动配置路径。
  2. 内存处理PDF:Vercel临时文件系统有读写限制,直接用Buffer传递附件更可靠。
  3. 异步文件读取:用fs/promises的异步方法,符合NextJS API的异步逻辑,避免阻塞。
  4. 环境变量存敏感信息:不要硬编码账号密码,用Vercel环境变量管理更安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:25:45