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

Firefox v117.0.1中Next.js+nookies过期Cookie未清除问题

问题描述

我正在开发一个使用nookies包处理Cookie的Next.js项目,项目包含两个带过期时间的Cookie。通过nookies.set(ctx, name, value, options)设置Cookie时,options中包含maxAge属性,预期Cookie过期后会被浏览器自动清除,但仅在Firefox v117.0.1中出现过期Cookie未清除的情况,其他浏览器表现正常。

自动登出后再次登录时,自定义AuthProvider组件读取到的token始终为undefined,登录后会被重定向回登录页,必须登录两次才能正常进入站点。该问题为近期出现,旧版Firefox无此情况。

相关代码

设置Cookie的代码

export const setUaaCookie = (access: string, refresh?: string): void => {
  const accessExpires = GetTokenExpireTime(access);
  const refreshExpires = GetTokenExpireTime(refresh);

  setCookie('access_token', access, {
    expires: accessExpires,
    path: '/',
    domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
  });
  setCookie('refresh_token', refresh, {
    expires: refreshExpires,
    path: '/',
    domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
  });
  request.setHeader('Authorization', `Bearer ${access}`);
};

AuthProvider认证逻辑代码

const authenticate = (): void => {
  // 获取浏览器Cookie
  const cookies = parseCookies();
  const hasToken = cookies.refresh_token;
  let isPrivateRoute = true;

  const publicRoutes = [
    '/account/login',
    '/account/otp-login',
    '/account/signup',
    '/account/forget-password',
  ];

  // 判断当前路由是公开路由还是私有路由
  if (
    publicRoutes.find(item => router.asPath.includes(item)) ||
    router.asPath === '/'
  )
    isPrivateRoute = false;

  if (isPrivateRoute && !hasToken) {
    goToLoginPage();
    setLoading(true);
    return;
  }

  if (!isPrivateRoute && hasToken) {
    const next = router.query.next || '/market-summary';
    router.push(next.toString());
    setLoading(true);
    return;
  }
  setLoading(false);
};

useEffect(() => {
  authenticate();
}, [router]); 

疑问

  1. 该问题的原因是什么?
  2. 如何在Next.js和Firefox v117.0.1中解决nookies相关的Cookie清除问题?
  3. 如何确保过期或已删除的Cookie从浏览器彻底清除,不影响自动登出功能?

解决方案

问题根源分析

Firefox v117.0.1在Cookie处理上存在兼容性异常:

  • 当domain属性设置为带前缀的非顶级域名(如.example.com)时,Firefox可能无法正确识别expires参数,导致过期Cookie未被清理。
  • nookies在新版本Firefox中可能存在expires与maxAge参数转换的bug,导致过期时间未被正确写入。
  • 自动登出后的重定向流程中,Firefox存在Cookie读取缓存,新设置的Cookie无法被及时读取,引发二次登录问题。

具体解决步骤

  1. 统一Cookie过期时间配置
    同时设置expires和maxAge属性,避免单一参数在Firefox中失效,同时补充secure和sameSite属性增强兼容性:

    export const setUaaCookie = (access: string, refresh?: string): void => {
      const accessExpires = GetTokenExpireTime(access);
      const refreshExpires = GetTokenExpireTime(refresh);
      // 计算maxAge(秒数)
      const accessMaxAge = Math.floor((accessExpires.getTime() - Date.now()) / 1000);
      const refreshMaxAge = Math.floor((refreshExpires.getTime() - Date.now()) / 1000);
    
      setCookie('access_token', access, {
        expires: accessExpires,
        maxAge: accessMaxAge,
        path: '/',
        domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
      });
      setCookie('refresh_token', refresh, {
        expires: refreshExpires,
        maxAge: refreshMaxAge,
        path: '/',
        domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
      });
      request.setHeader('Authorization', `Bearer ${access}`);
    };
    
  2. 主动清除过期Cookie
    在AuthProvider初始化时,主动检查并清除已过期的Cookie:

    const clearExpiredCookies = () => {
      const cookies = parseCookies();
      Object.entries(cookies).forEach(([name, value]) => {
        const expireTime = GetTokenExpireTime(value);
        if (expireTime && expireTime < new Date()) {
          destroyCookie(null, name, {
            path: '/',
            domain: process.env.NEXT_PUBLIC_COOKIE_DOMAIN,
          });
        }
      });
    };
    
    useEffect(() => {
      clearExpiredCookies();
      authenticate();
    }, [router]);
    
  3. 修复登录重定向逻辑
    登录成功后,等待Cookie写入完成再执行重定向,规避Firefox的缓存问题:

    // 登录成功回调中
    setUaaCookie(accessToken, refreshToken);
    setTimeout(() => {
      router.push(router.query.next || '/market-summary');
    }, 100);
    
  4. 修正domain属性格式

    • 本地开发时可省略domain,或设置为localhost
    • 生产环境设置为不带前缀的域名(如example.com,而非.example.com),避免Firefox域名匹配异常
  5. 更新nookies包
    升级到最新稳定版,修复已知兼容性bug:

    npm update nookies
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 19:14:53