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

Next.js生产环境鉴权跳转受保护页面报客户端异常

问题修复方案

根因定位

  • 直接触发客户端白屏报错的原因:useSession钩子的错误处理缺失空值校验。当接口返回500错误、跨域拦截、网络异常等场景时,Axios抛出的错误对象上response字段为undefined,直接读取error.response.data.redirectUrl会触发未捕获的JS异常,对应你看到的Application error: a client-side exception has occurred报错。
  • Cookie无法被服务端读取的核心原因:axios实例使用了拼接process.env.HOST的绝对路径作为baseURL,生产环境下只要HOST配置的协议、域名、端口和实际站点访问地址不一致,请求就会变成跨域请求。跨域场景下如果sid Cookie没有配置对应跨域策略,浏览器不会在请求中携带该Cookie,导致服务端拿不到会话标识。本地开发时HOST默认值为http://localhost:3000和本地访问地址一致,所以流程正常。
  • 冗余逻辑风险:checkSession函数中添加的typeof window === 'undefined'判断完全多余——该函数仅在Next.js服务端API路由中调用,运行环境永远不存在window对象,这类冗余判断在生产构建时可能被打包工具误判,导致逻辑分支异常。
  • 多节点配置不一致:axios baseURL、401重定向、登录跳转三处逻辑都独立读取HOST变量拼接地址,只要一处配置错误就会触发跳转、请求异常。

分步修复

1. 修复错误处理空值判断,解决客户端崩溃

修改src/services/apiClient中的useSession逻辑,增加可选链做空值保护:

export const useSession = () => {
    const router = useRouter()
    const { isLoading, error, data, isSuccess } = useQuery<Admin, AxiosError<RedirectError>>('sid', getSession)
    // 逐层判断属性存在后再执行跳转
    if (error?.response?.data?.redirectUrl) {
        router.push(error.response.data.redirectUrl)
    }
    return { isLoading, error, data, isSuccess }
}

2. 改用相对路径配置axios,从根源消除跨域问题

Next.js的API路由和前端页面同域部署,不需要配置绝对路径请求地址,直接修改axios实例配置,删除HOST拼接逻辑:

// 删除原有的host常量定义,修改axios实例配置
export const apiClient = axios.create({
    baseURL: "/api", // 相对路径自动匹配当前访问的协议、域名,不会触发跨域
    withCredentials: true,
    headers: {
        "Content-type": "application/json"
    },
});

同步修改api/getSession接口中的401重定向逻辑,不要拼接HOST,直接返回相对路径:

// 删除原有的host变量定义,直接返回站内相对地址
return res.status(401).send({ redirectUrl: '/admin/login' })

3. 清理checkSession中的冗余环境判断

删除无意义的window对象判断,简化逻辑:

export default async function checkSession (token: string) {
    if (!token) return null
    const unsign = (await import('./signature')).unsign
    const sessionToken = unsign(token, process.env.SECRET!)

    if (sessionToken && typeof sessionToken === 'string') {
        const db = (await import('../../prisma')).default
        const session = await db.session.findUnique({ 
            where: { sessionToken }, 
            include: { admin: true } 
        })
        if (session) {
            return { admin: session.admin }
        }
    }
    return null
}

4. 校正生产环境Cookie配置

找到登录接口写入sid Cookie的逻辑,按部署环境配置Cookie属性,避免浏览器拦截Cookie:

// 写入Cookie的参考配置
res.setHeader('Set-Cookie', serialize('sid', signedToken, {
    httpOnly: true, // 禁止前端JS读取Cookie,提升安全性
    secure: process.env.NODE_ENV === 'production', // HTTPS生产环境必须开启secure
    sameSite: 'lax', // 同域部署使用lax即可,兼容大部分场景
    path: '/',
    maxAge: 60 * 60 * 24 * 7 // 按实际会话有效期配置
}))

提示:如果确实存在跨域请求API的场景(Next.js同域部署无此需求),才需要将sameSite设为none,且必须同时开启secure属性,否则浏览器不会在跨域请求中携带该Cookie。

5. 生产环境变量校验

部署前确认生产环境的SECRET等必填环境变量已正确配置,避免因为环境变量缺失导致签名校验失败,接口返回500错误。


内容的提问来源于stack exchange,提问作者XAZG Неизвестный

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:40:00