为何Gatsby集合路由的jsonId值出现异常转换?
Gatsby集合路由中JSON ID自动转换为带连字符小写格式的问题
问题背景
使用gatsby-transformer-json插件查询JSON文件,项目目录结构如下:
src ├── data │ ├── channels │ │ └── UC7Lhhngb9lLW6tuPddEM62A.json │ │ ... │ └── videos │ └── K17df81RL9Y.json │ │ ...
视频JSON文件(src/data/videos/K17df81RL9Y.json)内容示例:
{ "id": "K17df81RL9Y", "title": "AURORA - Cure For Me (Official Video)", "channelId": "UC7Lhhngb9lLW6tuPddEM62A", "publishedAt": "2021-07-08T17:00:10Z", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/K17df81RL9Y/default.jpg", "width": 120, "height": 90 }, ... } }
在pages目录下创建了video/{VideosJson.jsonId}.js集合路由组件,代码如下:
import * as React from "react"; const VideoDetails = (params) => { return ( <main> <p>My blog post contents will go here (eventually).</p> <pre> <code dangerouslySetInnerHTML={{ __html: JSON.stringify(params, null, 2), }} /> </pre> </main> ); }; export default VideoDetails;
但生成的页面路径中,原始ID K17df81RL9Y 被转换为 k17df81-rl-9-y(大写转小写,大写字母前添加连字符),组件接收的params核心内容如下:
{ "path": "/video/k17df81-rl-9-y/", "pageContext": { "jsonId": "K17df81RL9Y", "__params": { "jsonId": "k17df81-rl-9-y" } }, "params": { "jsonId": "k17df81-rl-9-y" } }
集合路由官方文档未提及此行为,询问原因。
原因分析
这是Gatsby内置的**slug格式化(slugify)**机制导致的:
- Gatsby在处理集合路由的动态参数时,会自动对参数值做标准化处理,生成符合URL规范的路径片段
- 处理规则包括:将所有字母转为小写、在大写字母前插入连字符(拆分混合大小写的字符串)、移除或替换URL不允许的特殊字符
- 目的是保证URL的可读性、兼容性,同时符合SEO最佳实践
注意:虽然路径和params中的jsonId是格式化后的slug,但pageContext中仍然保留了原始的jsonId值(即K17df81RL9Y),可以直接从pageContext获取原始ID使用。
解决方案(保留原始ID作为路径)
如果需要保留原始ID作为路径参数,不使用自动格式化的slug,可以放弃集合路由,改用gatsby-node.js中的createPage API手动创建页面:
- 创建
gatsby-node.js文件,添加以下代码:
exports.createPages = async ({ graphql, actions }) => { const { createPage } = actions; // 查询所有视频JSON数据 const queryResult = await graphql(` query GetAllVideos { allVideosJson { nodes { id } } } `); // 遍历每个视频,创建对应页面 queryResult.data.allVideosJson.nodes.forEach(video => { createPage({ path: `/video/${video.id}/`, component: require.resolve("./src/pages/video/[id].js"), context: { id: video.id, }, }); }); };
- 将原集合路由文件
video/{VideosJson.jsonId}.js重命名为video/[id].js,并修改组件从pageContext获取原始ID:
import * as React from "react"; const VideoDetails = ({ pageContext }) => { const { id } = pageContext; return ( <main> <p>视频ID:{id}</p> <pre> <code>{JSON.stringify(pageContext, null, 2)}</code> </pre> </main> ); }; export default VideoDetails;
内容的提问来源于stack exchange,提问作者Sergio Flores
相关产品推荐
相关产品推荐

