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

Next.js组件中如何在服务端布局获取Slug?

解决Next.js App Router中布局组件服务端函数无法获取slug的问题

问题根源

根目录的app/layout.tsx是全局布局,它关联的generateMetadata无法直接获取页面路由中的slug参数——只有对应动态路由段的layout或page组件才能拿到该段的params。你当前把generateMetadata放在全局布局依赖的组件中再导出,本质还是根布局的元数据函数,自然拿不到页面的slug。

正确实现方式

1. 调整代码结构:将元数据逻辑移至动态路由段的组件中

如果你的slug来自app/[slug]/page.tsx这类动态路由,需要把generateMetadata放在该动态路由段的layout.tsx或page.tsx里,而非根布局。

2. 修正后的代码示例

动态路由段的layout(app/[slug]/layout.tsx)

import { Metadata } from "next";
import { fetchMetadata } from "@/lib/fetch-meta-data";
import { lora, poppins } from "@/app/fonts";

type Params = {
  slug: string;
};

type SearchParams = {
  [key: string]: string | string[] | undefined;
};

type Props = {
  params: Params;
  searchParams: SearchParams;
  children: React.ReactNode;
};

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = params;
  console.log(params, "Log params in generateMetadata");
  const pageMetadata = await fetchMetadata(slug);

  const defaultTitle = "Default App Name";
  const defaultDescription =
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
  const defaultImageUrl = `/images/default.jpg`;
  const pageTitle = pageMetadata?.title
    ? `${pageMetadata.title} | App Name`
    : defaultTitle;

  return {
    title: pageTitle,
    description: pageMetadata?.description || defaultDescription,
    keywords: pageMetadata?.keywords || "default, keywords",
    applicationName: "App Name",
    authors: [{ name: "App Name" }],
    publisher: "App Name",
    formatDetection: {
      email: false,
      address: false,
      telephone: false,
    },
    openGraph: {
      title: pageMetadata?.title || defaultTitle,
      description: pageMetadata?.description || defaultDescription,
      url: `/path/${slug}`,
      siteName: "App Name",
      images: [
        {
          url: pageMetadata?.imageUrl || defaultImageUrl,
          width: 1200,
          height: 630,
        },
      ],
      locale: "en_US",
      type: "website",
    },
    twitter: {
      card: "summary_large_image",
      title: pageMetadata?.title || defaultTitle,
      description: pageMetadata?.description || defaultDescription,
      images: [pageMetadata?.imageUrl || defaultImageUrl],
    },
    robots: {
      index: true,
      follow: true,
    },
  };
}

export default function SlugLayout({ children }: Props) {
  return (
    <div className={`${poppins.variable} ${lora.variable}`}>
      {children}
    </div>
  );
}

根layout(app/layout.tsx)

保留全局HTML/Body结构,不再处理元数据逻辑:

import ClientLayout from "@/components/layouts/main/client-layout";

export default function AppLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en-US" suppressHydrationWarning>
      <body suppressHydrationWarning>
        <ClientLayout>{children}</ClientLayout>
      </body>
    </html>
  );
}

3. 关键说明

  • App Router中,路由段的层级决定了params的可访问性:只有包含[slug]的路由段对应的layout/page,才能获取到该slug参数。
  • 若需在全局布局中使用slug数据,不能通过根布局的服务端函数直接获取,需从动态路由组件通过props传递给全局布局的客户端部分(但服务端函数如generateMetadata只能在对应路由段中运行)。
  • 旧的getServerSideProps是Pages Router的API,App Router已替换为generateMetadata、generateStaticParams等,请勿混用两种路由体系的API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:23:15