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

Next.js中generateStaticParams异常:自定义Slug被ID替代问题排查

问题:Next.js中generateStaticParams返回自定义slug失效,使用API的id作为slug

在Next.js项目中,尝试通过generateStaticParams生成自定义slug,但实际生效的slug是API返回的id,而非generateSlugs函数生成的自定义值。generateSlugs会返回包含自定义slug和id的对象数组,但generateStaticParams未正确使用自定义slug。


页面组件代码

import Gallery from "@/app/components/Gallery";
import ProductDescription from "@/app/components/ProductDescription";
import Navbar from "@/app/layout/Navbar";
import ProductSection from "@/app/layout/ProductSection";
import Products from "@/app/layout/Products";
import { Metadata, ResolvingMetadata } from "next";
import { notFound } from "next/navigation";
import { Slug } from "@/app/types/types";
import { ProductPage } from "@/app/types/types";
import { getData } from "@/app/utils/getData";
import generateSlugs from "@/app/utils/generateSlugs";

export const preferredRegion = ["fra1"];
export const dynamic = "force-dynamic";

export async function generateStaticParams() {
  const params = await fetch(`${process.env.API_URL}/api/auctions`).then(
    (res) => res.json()
  );

  const slugs = generateSlugs(params);

  return slugs.map((slug: Slug) => ({
    slug: slug.slug,
  }));
}

export async function generateMetadata(
  { params }: { params: Slug },
  parent: ResolvingMetadata
): Promise<Metadata> {
  console.log(params);

  const product = await getData(params);
  const url = "https://noanzo.pl";
  return {
    title: `${product[0]?.title} - noanzo.pl`,
    description: product[0]?.description,
    robots: "index, follow",
    alternates: {
      canonical: `${url}/produkt/${params.slug}`,
    },
    openGraph: {
      title: `${product[0]?.title} - noanzo.pl`,
      description: product[0]?.description,
      locale: "pl",
      images: [
        {
          url: (() => {
            const link = product[0]?.image.filter(
              (item: any) => item.thumbnail === true
            );
            if (!product[0]) {
              notFound();
            }
            if (link[0]?.url) {
              return link[0].url;
            } else {
              return product[0].image[0].url;
            }
          })(),
          alt: product[0]?.title,
        },
      ],
    },
  };
}

export default async function Page({ params }: { params: Slug }) {
  const data = await getData(params);
  if (!data || data[0] === null) {
    notFound();
  }
  const product: ProductPage = {
    title: data[0].title,
    description: data[0].description,
    price: data[0].price,
    image: data[0].image,
    imageLarge: data[0].imageLarge,
  };

  return (
    <main>
      <Navbar />
      <div className='container mx-auto sm:w-4/5 lg:w-11/12 xl:sm:w-4/5 p-2'>
        <ProductSection>
          <Gallery product={product} />
          <ProductDescription product={product} />
        </ProductSection>
      </div>
      <Products />
    </main>
  );
}

测试用的generateStaticParams代码(直接使用API返回值)

export async function generateStaticParams() {
  const params = await fetch(`${process.env.API_URL}/api/auctions`).then(
    (res) => res.json()
  );

  return params.map((slug: Slug) => ({
    slug: slug.slug,
  }));
}

这段代码可运行,但返回的slug是API返回条目中的id,而非自定义生成的slug。


generateSlugs工具函数代码

const generateSlugs = (params: Array<any>) => {
  const slugs = params.map((item: any) => {
    let slug = item.title.replace(/\s+/g, "-");
    if (!slug.endsWith("-")) {
      slug = slug + "-";
    }
    slug = slug + item.id.substring(0, 8);
    return { slug: slug.toLowerCase(), id: item.id };
  });
  return slugs;
};

export default generateSlugs;

问题原因分析

  1. dynamic: "force-dynamic"配置冲突:这个配置会强制页面完全动态渲染,直接跳过generateStaticParams生成静态参数的逻辑,导致自定义slug被忽略,转而使用动态请求中的参数(此处为API返回的id)。
  2. getData函数逻辑不匹配:如果getData函数是通过params.slug去API查询数据,但API仅识别id而非自定义slug,会导致查询失败,Next.js可能会 fallback 到使用id作为路由参数。
  3. 类型定义可能存在偏差:若Slug类型中slug字段的定义与实际数据结构不匹配(比如误将API的id映射为slug),会导致编译时无法检测到参数传递错误。

解决步骤

  1. 移除dynamic: "force-dynamic":若需要静态生成页面,删除该配置,让generateStaticParams生效。
  2. 调整generateStaticParams返回结构:同时返回自定义slug和id,确保查询数据时使用正确的标识:
export async function generateStaticParams() {
  const params = await fetch(`${process.env.API_URL}/api/auctions`).then(res => res.json());
  const slugs = generateSlugs(params);
  return slugs.map(item => ({ 
    slug: item.slug, 
    id: item.id 
  }));
}
  1. 修改getData函数:使用id而非slug查询数据:
export async function getData(params: { slug: string; id: string }) {
  const res = await fetch(`${process.env.API_URL}/api/auctions/${params.id}`);
  return res.json();
}
  1. 验证Slug类型定义:确保类型与实际返回结构一致:
// @/app/types/types.ts
export interface Slug {
  slug: string;
  id: string;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:25:02