next 13 next/cookie不是动态的,页面缓存时中间件无法访问

z31licg0  于 2023-08-04  发布在  其他
关注(0)|答案(1)|浏览(128)

这是我第一次在这里发帖,但我搜索了很多链接和论坛,从来没有找到一个适合我的答案…我在cookie中保存了一个jwt,并在nextjs中使用了一个中间件来检查用户是否经过了很好的身份验证,以及它的令牌是否尚未过期。我的问题是Next JS自动兑现所有页面,所以当我去例如“/home/chat”,中间件被触发,路由是安全的,用户可以访问页面,只有当他连接,但如果我回到这个页面,它已经兑现,所以它永远不会再次触发中间件,所以用户可以访问它,即使它的令牌不再有效,它会导致一些问题。我在文档中添加了“export const dynamic = 'force-dynamic'”或“export const revalidate = 0”,但它们是一样的。此外,我在文档中看到,使用cookie()函数会自动将页面置于动态状态,但无论我做什么,中间件都不会再次触发,甚至页面中的console.log()也只会第一次触发,不会再次触发。这是我的“/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}/>
    )
}

字符串
谢谢你花时间阅读我和任何帮助!
所以我看到之前我们必须使用gerServerSideProps函数,但这是在下一个13的应用程序目录之前。我看到了这个文档“很高兴知道:cookie()是一个动态函数,其返回值无法提前知道。在布局或页面中使用它将在请求时选择动态呈现的路线。“但它仍然不是动态的,我不知道这是一个错误还是我还不明白的东西。也许这是我不明白的东西,但当我说它仍然不是动态的,我的意思是,console.log和中间件中的其他功能被触发,例如,我第一次去聊天页面。然后当我回来的时候,中间件中没有日志和动作。。
我所期望的是在访问每个页面之前通过这个中间件:

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).*)',
  ],
};


该中间件的目的是获取令牌,验证它,并允许人们访问受限页面或将其重定向到身份验证页面。
第一次编辑:非常感谢您的帮助,现在我希望我的中间件每次都被触发,但我的服务器组件也被触发,因为它们在cookie中获取用户数据及其令牌。正如我在文档中所说,如果我使用cookie()函数,它将是动态的,但现在它们在开始时被编译,并且永远不会再次运行。
下面是我的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');
    }
}


除此之外,
console.log(“ChatPage”)
在聊天页面上的服务器端记录只是我第一次去这个页面例如,即使它需要得到的饼干.我发现的一个解决方案是将此客户端组件添加到服务器组件中:

// Sample Refresher Component
// to be imported into SSR page
// needing a refresh after 
// next.js appDir Link nav
//

'use client'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'

export function Refresher() {
    const router = useRouter()

    useEffect(() => {
        router.refresh()
    }, [router])

    return <></>
}


这是一个非常丑陋的方法,我不想这样做,因为我目前正在编写一个单页应用程序,但这是我发现的唯一方法,在第一次访问我的页面之前运行中间件。
有人能帮帮我吗?

h22fl7wq

h22fl7wq1#

是的,Next.js确实会在第一次访问时缓存页面。这意味着返回到它本质上不会重新运行中间件。
但是,如果刷新页面,则会强制重新呈现页面,从而重新运行中间件;你可以使用console.logs来检查正在运行的中间件。
中间件将100%运行在config下的任何路由上,所以问题一定出在令牌逻辑或条件上。
请提供您的verifyAuth代码,因为问题可能就在那里。

相关问题