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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 10:42:38