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;
问题原因分析
dynamic: "force-dynamic"配置冲突:这个配置会强制页面完全动态渲染,直接跳过generateStaticParams生成静态参数的逻辑,导致自定义slug被忽略,转而使用动态请求中的参数(此处为API返回的id)。getData函数逻辑不匹配:如果getData函数是通过params.slug去API查询数据,但API仅识别id而非自定义slug,会导致查询失败,Next.js可能会 fallback 到使用id作为路由参数。- 类型定义可能存在偏差:若
Slug类型中slug字段的定义与实际数据结构不匹配(比如误将API的id映射为slug),会导致编译时无法检测到参数传递错误。
解决步骤
- 移除
dynamic: "force-dynamic":若需要静态生成页面,删除该配置,让generateStaticParams生效。 - 调整
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 })); }
- 修改
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(); }
- 验证
Slug类型定义:确保类型与实际返回结构一致:
// @/app/types/types.ts export interface Slug { slug: string; id: string; }
内容的提问来源于stack exchange,提问作者Marcin Czaja
相关产品推荐
相关产品推荐

