Next.js频繁创建动态页面数据获取:解决Prisma浏览器运行报错
解决方案:Next.js + Prisma 动态页面数据获取最佳实践
错误原因
PrismaClient 是服务端专属工具,只能在 Node.js 环境运行,无法在浏览器端执行,所以你不能在客户端组件或直接在浏览器环境中调用 Prisma 相关代码——所有数据库操作必须放在服务端执行。
可行方案
方案1:API 路由 + SWR(适配 Pages Router/App Router)
这是你当前思路的正确落地方式:把 Prisma 查询逻辑放在 Next.js 的 API 路由中(服务端运行),客户端用 SWR 调用这个 API 接口获取数据。
步骤1:编写服务端 API 路由
- Pages Router 示例(
pages/api/survey-data.js):
import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default async function handler(req, res) { // 只处理 GET 请求 if (req.method !== 'GET') { return res.status(405).json({ error: '仅支持 GET 请求' }) } try { // 替换成你的实际查询逻辑 const survey = await prisma.survey.findFirst({ // 可选:添加查询条件、关联字段等 // where: { id: req.query.id }, // include: { questions: true } }) res.status(200).json({ survey }) } catch (err) { res.status(500).json({ error: '获取数据失败' }) } finally { // 断开 Prisma 连接 await prisma.$disconnect() } }
- App Router 示例(
app/api/survey-data/route.js):
import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export async function GET() { try { const survey = await prisma.survey.findFirst() return Response.json({ survey }) } catch (err) { return Response.json({ error: '获取数据失败' }, { status: 500 }) } finally { await prisma.$disconnect() } }
步骤2:客户端 SWR 调用(你的现有代码可直接复用)
确保客户端组件中没有导入 PrismaClient,仅调用 API 接口:
const fetcher = (...args) => fetch(...args).then((res) => res.json()); export default function View() { const { data, isLoading, error } = useSWR('/api/survey-data', fetcher); const survey = data?.survey; if(error) return <div>加载失败</div>; if(isLoading) return <Loading/>; // 渲染 survey 内容 return <div>{survey?.title}</div> }
方案2:Server Component 直接查询(App Router 专属)
如果你的页面不需要客户端侧的数据刷新或复杂交互,可直接在 Server Component 中编写 Prisma 查询——Server Component 默认在服务端运行,无需额外 API 路由:
// app/view/page.js(默认是 Server Component) import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient() export default async function View() { try { const survey = await prisma.survey.findFirst() if (!survey) return <div>未找到问卷数据</div> return <div> <h1>{survey.title}</h1> <p>{survey.description}</p> </div> } catch (err) { return <div>加载数据失败</div> } finally { await prisma.$disconnect() } }
方案3:ISR(增量静态再生)(解决原 getStaticProps 痛点)
如果你仍想使用静态生成,但需要动态更新数据,可启用 ISR:在 getStaticProps 中添加 revalidate 参数,让页面在后台自动重新生成:
export async function getStaticProps() { const prisma = new PrismaClient() const survey = await prisma.survey.findFirst() await prisma.$disconnect() return { props: { survey }, // 每 60 秒重新生成页面(可根据需求调整) revalidate: 60 } } export async function getStaticPaths() { return { paths: [], // 或生成动态路径 fallback: 'blocking' // 或 'true',根据场景选择 } }
关键注意事项
- 永远不要在客户端组件中导入或使用 PrismaClient
- 服务端代码中,每次查询后建议断开 Prisma 连接,或使用 Prisma 连接池优化
- SWR 适合需要客户端缓存、后台重新验证数据的场景;Server Component 适合无需客户端交互的静态/动态页面;ISR 适合需要静态生成+定期更新的场景
内容的提问来源于stack exchange,提问作者lynx
相关产品推荐
相关产品推荐

