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

Next.js 13页面缓存致Middleware与动态页面失效问题求助

Next.js 13 App目录下Middleware缓存问题:Token失效后仍可访问页面

问题背景

我基于Next.js 13 App目录开发,通过Cookie存储JWT,依赖Middleware校验用户认证状态与Token有效性。当前遇到页面自动缓存的问题:

  • 首次访问/home/chat时,Middleware正常触发,路由校验逻辑正常执行
  • 再次返回该页面时,页面已被缓存,Middleware不再触发,即便用户Token失效,仍能直接访问页面,引发权限安全问题

已尝试的解决方案(均无效)

  • 按官方文档要求,在页面中添加export const dynamic = 'force-dynamic'或export const revalidate = 0,未改变缓存行为
  • 官方文档说明调用cookies()函数会自动将页面设为动态渲染状态,但实际页面仍保持缓存,页面内的console.log()仅在首次访问时打印
  • 临时方案:在Server Components中引入客户端组件调用router.refresh(),但破坏了单页应用的体验,不符合需求

相关代码

/home/chat页面代码

import { cookies } from "next/headers";
import Link from "next/link";
import styles from "@/styles/chatPage/ChatPage.module.css";
import ChatClient from "@/components/chatPage/ChatClient";
import Profile_Service from "@/services/Profile.service";

export default async function ChatPage() {
    let     token: string | undefined;
    let     myself: Profile & { avatar: Avatar };

    console.log("chat page");
    try {
        token = cookies().get("crunchy-token")?.value;
        if (!token)
            throw new Error("No token value");

        const profilService = new Profile_Service(token);
        myself = await profilService.getProfileAndAvatar();

    } catch (err) {
        console.log(err);
        return (
            <div className={styles.error}>
                <h2>Oops... Something went wrong!</h2>
                <Link href="/home" className={styles.errorLink}>
                    <p>Return to Home Page!</p>
                </Link>
            </div>
        )
    }

    return (
        <ChatClient token={token} myself={myself}/>
    )
}

Middleware代码

import { verifyAuth } from "@/lib/auth/auth";
import { NextRequest, NextResponse } from "next/server";

export async function middleware(req: NextRequest) {
  const crunchyToken = req.cookies.get("crunchy-token")?.value;

  const verifiedToken =
    crunchyToken &&
    (await verifyAuth(crunchyToken).catch((err) => {
      console.log(err);
    }));
  const url = req.nextUrl;
  console.log(verifiedToken, url);

  if (
    verifiedToken &&
    verifiedToken.login &&
    req.nextUrl.pathname === "/home/create"
  ) {
    return NextResponse.redirect(new URL("/home", req.url));
  }

  if (
    verifiedToken &&
    !verifiedToken.login &&
    req.nextUrl.pathname.startsWith("/home") &&
    req.nextUrl.pathname !== "/home/create"
  ) {
    return NextResponse.redirect(new URL("/home/create", req.url));
  }

  if (req.nextUrl.pathname === "/" && !verifiedToken) {
    return NextResponse.redirect(new URL("/welcome", req.url));
  }

  if (req.nextUrl.pathname === "/" && verifiedToken) {
    return NextResponse.redirect(new URL("/home", req.url));
  }

  if (req.nextUrl.pathname.startsWith("/welcome") && verifiedToken) {
    return NextResponse.redirect(new URL("/home", req.url));
  }

  if (req.nextUrl.pathname.startsWith("/home") && !verifiedToken) {
    return NextResponse.redirect(new URL("/welcome", req.url));
  }
}

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - icon, images
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|icon|images|_next/static|_next/image|favicon.ico).*)',
  ],
};

verifyAuth函数代码

import { jwtVerify} from "jose";

export const verifyAuth = async (token: string) => {

    try {
        const verified = await jwtVerify(
            token,
            new TextEncoder().encode(process.env.JWT_SECRET),
        );
        
        return verified.payload;

    } catch (error) {
        throw new Error('Your token has expired');
    }
}

核心诉求

  • 确保每次访问页面时,Middleware都会触发,严格执行Token校验逻辑
  • Server Components能通过Cookie中的Token获取用户数据,且每次访问都重新执行相关逻辑(而非仅初始编译时执行一次)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 01:38:34