Next.js 14中Layout.js获取localStorage及页面权限校验问题
解决方案:Next.js 14 页面校验 localStorage 并重定向
你的核心问题在于:默认的 Layout 是服务器组件(SSR),无法访问浏览器端的 localStorage;但直接加 "use client" 又会影响 metadata 的使用(metadata 仅支持服务器组件)。下面提供两种可行的调整方案:
方案一:保留 metadata,拆分客户端校验逻辑
把校验逻辑抽成独立的客户端组件,让原 Layout 保持服务器组件身份以保留 metadata:
- 创建客户端校验组件
AuthCheck.js:
"use client"; import { useEffect } from "react"; import { useRouter } from "next/navigation"; export default function AuthCheck({ children }) { const router = useRouter(); useEffect(() => { const apiKey = localStorage.getItem("api-key"); if (!apiKey) { router.push("/"); } }, [router]); return <>{children}</>; }
- 修改原 Layout 组件,引入并使用
AuthCheck:
import * as React from "react"; import AuthCheck from "./AuthCheck"; export const metadata = { title: "My Profile", }; export default function StarforceProfileLayout({ children }) { return <AuthCheck>{children}</AuthCheck>; }
说明:原 Layout 仍为服务器组件,metadata 正常生效;校验逻辑在客户端执行,确保只有存在 api-key 的用户才能看到页面内容。
方案二:放弃 metadata,改为客户端组件直接处理
如果对 SEO 要求不高,可以把整个 Layout 改为客户端组件,直接在里面完成标题设置和校验:
"use client"; import { useEffect } from "react"; import { useRouter } from "next/navigation"; export default function StarforceProfileLayout({ children }) { const router = useRouter(); useEffect(() => { // 客户端设置页面标题 document.title = "My Profile"; // 校验 localStorage 中的 api-key const apiKey = localStorage.getItem("api-key"); if (!apiKey) { router.push("/"); } }, [router]); return <>{children}</>; }
说明:这种方式无需拆分组件,但页面标题是在客户端渲染后才设置的,搜索引擎爬虫可能无法抓取到正确标题,适合对 SEO 要求较低的场景。
关键注意点
- 服务器组件(默认无
"use client")无法访问浏览器 API(如localStorage、document),这类操作必须放在客户端组件中执行。 redirect()是服务器组件专用的重定向方法,客户端组件中需使用useRouter的push/replace方法。
内容的提问来源于stack exchange,提问作者mmd
相关产品推荐
相关产品推荐

