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

迁移至Supabase后NextJS工具函数随机调用失败求助

问题描述

我基于NextJS、Prisma、Supabase(近期从PlanetScale迁移)及Clerk认证开发了Web应用。启动应用时,获取用户/企业数据的工具函数会调用失败,提示无法读取返回数据的某个属性,但刷新页面后服务器又能成功获取数据。已为函数添加try/catch块,Supabase模型也配置了RLS规则,使用PlanetScale时未出现该问题,不确定是网络速度不佳、工具函数写法有误还是Supabase配置不当导致。

示例工具函数

获取用户信息函数

export const getUserByClerkID = async () => {
  const { userId } = await auth()
  //console.log('CLERK USER ID ', userId)
  try {
    const user = await prisma.user.findUnique({
      where: {
        clerkId: userId,
      },
    })
    return user
  } catch (error) {
    console.error('Error fetching user by clerk ID', error)
  }
}

获取企业数据函数

export const fetchOrgData = async () => {
  const user = await getUserByClerkID()
  console.log('USER WHILE FETCHING ORG DATA', user)
  try {
    const orgData = await prisma.company.findFirst({
      where: {
        employees: {
          some: {
            clerkId: user.clerkId,
          },
        },
      },
      include: {
        employees: true,
        teams: true,
        savedCandidates: true,
        messageThreads: true,
      },
    })

    return orgData
  } catch (error) {
    console.error('Error fetching org data', error)
  }
}
排查思路与解决方案

1. 认证时机校验

auth()在NextJS组件/路由初始化阶段可能未完成认证,导致userId为undefined,进而getUserByClerkID返回undefined,后续fetchOrgData访问user.clerkId直接报错。

  • 修复方案:在函数中增加空值判断,避免无效调用:
    修改getUserByClerkID:
    export const getUserByClerkID = async () => {
      const { userId } = await auth()
      if (!userId) {
        console.warn('未获取到Clerk用户ID')
        return null
      }
      try {
        const user = await prisma.user.findUnique({
          where: {
            clerkId: userId,
          },
        })
        return user
      } catch (error) {
        console.error('通过Clerk ID获取用户失败', error)
        return null
      }
    }
    
    修改fetchOrgData:
    export const fetchOrgData = async () => {
      const user = await getUserByClerkID()
      if (!user) {
        console.warn('无有效用户,无法获取企业数据')
        return null
      }
      try {
        const orgData = await prisma.company.findFirst({
          where: {
            employees: {
              some: {
                clerkId: user.clerkId,
              },
            },
          },
          include: {
            employees: true,
            teams: true,
            savedCandidates: true,
            messageThreads: true,
          },
        })
    
        return orgData
      } catch (error) {
        console.error('获取企业数据失败', error)
        return null
      }
    }
    

2. Supabase RLS规则验证

迁移后RLS规则可能存在逻辑漏洞,或者Prisma连接Supabase时未正确传递认证上下文,导致首次请求被RLS拦截返回空数据。

  • 检查RLS规则:确保user和company表的规则允许当前认证用户访问对应数据。例如user表规则应限定仅能访问自身数据:
    CREATE POLICY "用户仅能查看自身数据" ON public.user
    FOR SELECT USING (auth.uid() = id);
    
  • 确认Prisma连接时是否注入Clerk认证信息:在NextJS Server Component中,需保证auth()返回的用户信息能被Supabase的RLS识别,可在Prisma客户端初始化时传递Supabase JWT。

3. 异步数据加载优化

若在客户端组件直接调用这些函数,首次渲染时异步数据未返回就尝试访问属性会报错,刷新后数据已缓存则正常。

  • 修复方案:在Server Component中预取数据,或使用useSWR/react-query等缓存库处理异步请求,确保数据加载完成后再渲染相关内容。

4. 网络连接重试配置

首次启动时Supabase连接初始化慢可能导致请求超时失败,刷新后连接已建立则请求成功。

  • 修复方案:给Prisma请求添加重试逻辑,或在Prisma配置中设置连接超时与重试次数:
    在prisma/schema.prisma中修改:
    datasource db {
      provider = "postgresql"
      url      = env("DATABASE_URL")
      shadowDatabaseUrl = env("SHADOW_DATABASE_URL")
      connectTimeout = 10 // 连接超时时间(秒)
      poolTimeout = 10 // 池超时时间(秒)
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 19:19:51