为何构建NextJS项目时API Routes会被调用?如何避免数据库新增数据?
解决Next.js API路由构建时预执行导致数据库重复写入的问题
问题描述
我有一个仅在Vercel设置的CRON任务中调用的API路由,负责向数据库生成数据。但每次构建项目时,数据库都会新增数据,推测是Next.js预执行端点以生成缓存的特性导致的,请问该如何避免?
解决方案
1. 禁用API路由的静态预渲染
Next.js默认会对GET类型的API路由做静态优化,在构建阶段预执行并生成缓存,这就是导致构建时数据库写入的核心原因。只需添加一行配置,强制路由每次请求都动态执行:
export const dynamic = 'force-dynamic'; // 关键配置:禁用静态预渲染 export const revalidate = 60 * 60 * 24 * 6; // every 6 days export async function GET(request: Request) { // 你的原有业务逻辑代码 }
2. 验证请求来源,仅允许CRON触发
为了进一步确保只有Vercel的CRON任务能触发数据库写入,可以验证请求签名:
Vercel的CRON任务会自动携带x-vercel-signature请求头,你可以用官方工具验证这个签名的合法性:
import { verifySignature } from '@vercel/signature'; export async function GET(request: Request) { // 验证签名,过滤非法请求 const signature = request.headers.get('x-vercel-signature'); if (!signature) { return NextResponse.json({ message: '无权限访问' }, { status: 401 }); } try { // CRON_SECRET需要在Vercel环境变量中配置,CRON任务设置时使用相同密钥 await verifySignature(request, process.env.CRON_SECRET!); } catch (error) { return NextResponse.json({ message: '无权限访问' }, { status: 401 }); } // 你的原有业务逻辑代码 }
3. 数据库层拦截重复数据
在执行写入操作前,先检查数据库中是否已存在相同时间周期(timeframe)的数据,避免重复插入:
async function addTokensDrawn(data: any) { try { // 检查当前timeframe是否已有数据 const existingRecord = await prisma.tokenDrawn.findFirst({ where: { timeframe: data[0].timeframe } }); if (existingRecord) { return NextResponse.json({ message: '数据已存在' }, { status: 200 }); } await prisma.tokenDrawn.createMany({ data }); return NextResponse.json({ message: '添加成功' }, { status: 200 }); } catch (error) { console.error("请求错误", error); return NextResponse.json({ message: '添加失败' }, { status: 500 }); } }
推荐方案组合
优先使用方案1+方案3:既从根源上阻止构建时的预执行,又在数据库层做重复拦截,双重保障数据不重复。如果需要更高的安全性,再加上方案2的签名验证。
内容的提问来源于stack exchange,提问作者Guilherme Felipe Reis
相关产品推荐
相关产品推荐

