Next.js使用getStaticPaths时如何实现动态URL掩码替换ID参数
解决方案
这个需求在Next.js中完全可以实现,404问题由动态路由参数配置、Link组件用法、自定义express服务器逻辑三者不匹配导致,按以下步骤调整即可:
方案一:优先推荐(无需自定义express服务器,用Next.js原生路由)
如果没有强制需要自定义express服务器的场景,直接删除server.js中自定义的/products/:id路由,用Next.js原生SSG路由实现,步骤如下:
- 调整动态路由文件名
将pages/products/[id].js重命名为pages/products/[slug].js,其中slug就是需要显示在URL里的product-1这类友好标识,需确保所有产品的slug全局唯一。 - 修改GraphQL查询逻辑
首先在查询所有产品的语句中增加slug字段的查询:const GET_ALL_QUERY = gql` { products { id slug // 对应后台存储的产品友好路径字段,未提前存储的话也可以在map的时候按规则生成,比如`product-${序号}` } } `; - 调整getStaticPaths配置
把返回的params参数和路由动态段对应:export async function getStaticPaths() { const paths = await client .query({ query: GET_ALL_QUERY }) .then((data) => { const productsData = data.data.products; return productsData.map((res, index) => { // 未预存slug可直接在此处生成:const slug = `product-${index+1}` return { params: { slug: res.slug } }; }); }) .catch((err) => Promise.reject(new Error(err))); return { paths, fallback: false, }; } - 调整getStaticProps查询逻辑
用slug作为参数查询单个产品(需要GraphQL接口支持按slug查询产品,不支持的话可以提前维护一份slug到产品ID的映射表):export async function getStaticProps({ params }) { try { const res = await client.query({ query: GET_ONE_QUERY, variables: { slug: params.slug }, // 替换原有按ID查询的逻辑 }); return { props: res.data.product, }; } catch (err) { throw new Error(err); } } - 简化Link组件写法
不需要再用as属性,直接拼接slug即可:<Link href={`/products/${product.slug}`}> 产品链接 </Link>
方案二:保留自定义express服务器
如果必须保留自定义express服务器,需要调整路由逻辑,把URL中的slug映射为真实的产品ID:
- 提前在内存中维护一份slug到产品ID的映射表,在服务启动时查询所有产品生成:
// 服务启动时预生成映射表 let slugToIdMap = {}; client.query({ query: GET_ALL_QUERY }).then(data => { data.data.products.forEach((product, index) => { const slug = `product-${index+1}`; // 按实际规则生成slug slugToIdMap[slug] = product.id; }); }); - 修改express路由逻辑,把slug转为真实ID再传给Next.js渲染:
server.get("/products/:slug", (req, res) => { const actualPage = "/products/[id]"; const realId = slugToIdMap[req.params.slug]; if(!realId) return res.status(404).send("产品不存在"); const queryParams = { id: realId }; app.render(req, res, actualPage, queryParams); }); - Link组件按原有写法即可,注意href对应实际路由:
<Link href={`/products/${product.id}`} as={`/products/${product.slug}`}> 产品链接 </Link>
内容的提问来源于stack exchange,提问作者RGog
相关产品推荐
相关产品推荐

