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

Vercel部署NextAuth会话校验失败:本地正常线上504错误排查

问题描述

我开发了一个博客,需要在用户访问创建文章页面时校验其管理员身份。该功能在本地运行正常,但部署到Vercel后出现504错误,日志无有效信息。我已将NEXTAUTH_URL改为Vercel提供的HTTPS地址。

相关代码

NewPostPage 代码

const NewPostPage = (props) => {
  if (props.messageError) {
    console.log("Error auth: " + props.messageError);
  }
  return (
    <div className={classes.pageContainer}>
      <NewPostForm />
    </div>
  );
};

export default NewPostPage

export const getServerSideProps = async (context) => {
  try {
    return await requireAuthentification(context, "admin", ({ session }) => {
      return {
        props: { session, messageError: null },
      }
    })
  }
  catch (error) {
    return {
      props: {
        messageError: error
      }
    }
  }
}

requireAuthentification 函数代码

const requireAuthentification = async (context, levelAcces = "public", callback) => {
    const session = await unstable_getServerSession(context.req, context.res, authOptions)
    if (!session) {
        return {
            redirect: {
                destination: '/',
                permanent: false,
            }
        }
    }
    else {
        let user = [];
        const q = query(collection(db, "users"), where("email", "==", session.user.email));
        const querySnapshot = await getDocs(q);
        user = querySnapshot.docs[0].data();
        if (user.level !== levelAcces) {
            return {
                redirect: {
                    destination: '/',
                    permanent: false,
                }
            }
        }
    }
    return callback({ session });
}

export default requireAuthentification

移除getServerSideProps后页面可正常访问但无路由安全校验,我怀疑问题出在unstable_getServerSession,使用GetSession也有同样问题,Vercel日志无法提供有效调试信息。请问为何本地正常线上异常?如何调试?


问题分析与解决方案

本地正常、线上504的核心原因

  1. Firebase请求超时
    服务端直接请求Firebase查询用户权限时,Vercel服务器与Firebase的跨区域网络延迟、防火墙限制等,会导致请求超时触发504。本地环境网络链路短,不会出现这类问题。

  2. NextAuth配置不全
    即使改了NEXTAUTH_URL,线上环境还需显式配置NEXTAUTH_SECRET(本地可自动生成,线上必须手动设置),否则unstable_getServerSession可能无法正常解析session。另外authOptions里的依赖配置(比如回调函数)若依赖本地环境变量,线上也会失效。

  3. 不稳定API兼容性问题
    unstable_getServerSession标记为测试API,可能在Vercel的Node.js运行环境中存在隐性bug,换用稳定版getServerSession(NextAuth v4.23+推荐)可规避这类问题。

调试与修复方案

  1. 添加精准日志定位卡点
    在requireAuthentification关键步骤插入日志,查看Vercel的函数日志(而非普通应用日志)定位问题:

    const requireAuthentification = async (context, levelAcces = "public", callback) => {
        console.log("[Auth] Start session fetch");
        const session = await unstable_getServerSession(context.req, context.res, authOptions)
        console.log("[Auth] Session fetched:", session ? "success" : "null");
        
        if (!session) {
            console.log("[Auth] No session, redirect");
            return { redirect: { destination: '/', permanent: false } }
        }
    
        console.log("[Auth] Fetch user from Firebase:", session.user.email);
        const q = query(collection(db, "users"), where("email", "==", session.user.email));
        // 给Firebase请求加超时控制
        const querySnapshot = await Promise.race([
            getDocs(q),
            new Promise((_, reject) => setTimeout(() => reject(new Error("Firebase query timeout")), 5000))
        ]);
        
        console.log("[Auth] Firebase query result count:", querySnapshot.docs.length);
        const user = querySnapshot.docs[0].data();
        console.log("[Auth] User level:", user.level);
    
        if (user.level !== levelAcces) {
            console.log("[Auth] Level mismatch, redirect");
            return { redirect: { destination: '/', permanent: false } }
        }
    
        console.log("[Auth] Auth passed");
        return callback({ session });
    }
    
  2. 优化Firebase访问逻辑

    • 检查Firebase IAM权限:确保服务端密钥拥有users集合的读取权限,避免因权限不足导致请求卡住。
    • 缓存用户权限到NextAuth Session:在authOptions的回调中把用户level注入session,避免每次请求都查询Firebase:
      // authOptions配置示例
      export const authOptions = {
          session: { strategy: "jwt" },
          callbacks: {
              async jwt({ token, user }) {
                  if (user) {
                      const q = query(collection(db, "users"), where("email", "==", user.email));
                      const querySnapshot = await getDocs(q);
                      token.level = querySnapshot.docs[0].data().level;
                  }
                  return token;
              },
              async session({ session, token }) {
                  session.user.level = token.level;
                  return session;
              }
          }
      }
      
      之后requireAuthentification可直接从session.user.level校验,无需再请求Firebase。
  3. 调整Vercel函数超时
    Vercel Serverless函数默认超时10秒,可在vercel.json中调整最大超时(上限15秒):

    {
        "functions": {
            "pages/api/**/*.js": {
                "maxDuration": 15
            }
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 13:16:01