Next.js 13动态路由服务组件Sanity数据获取失败
Next.js 13 Server Component 无法从 Sanity 获取动态路由数据问题
我在使用 Next.js 13 开发网站时,尝试在动态路由的 Server Component 中通过 Sanity Client 获取指定项目数据,但始终返回空结果。控制台日志显示查询语句格式正确,但就是拿不到数据。
相关代码
动态路由页面代码
import React from 'react' import { client } from '@/lib/sanityClient'; export default async function Page({params}) { const query = `*[type == "project" && _id == "${params.id}"]`; const project = await client.fetch(query , { cache: 'force-cache' }); console.log(query); console.log(project) return ( <div> <h1> Dummy static text</h1> <h1>{project.name}</h1> <p>{project.description}</p> </div> ) }
Sanity Schema 定义
export default { name: 'project', title: 'Project', type: 'document', fields: [ { name: 'name', title: 'Name', type: 'string', validation: (Rule) => Rule.required().max(100), }, { name: 'description', title: 'Description', type: 'text', validation: (Rule) => Rule.required().max(500), }, { name: 'images', title: 'Images', type: 'array', of: [ { type: 'image', options: { hotspot: true, }, }, ], validation: (Rule) => Rule.required().min(1), }, ], };
Sanity Client 配置
import { createClient } from "next-sanity"; import imageUrlBuilder from '@sanity/image-url'; export const client = createClient({ projectId: "7guc57bn", dataset: "production", apiVersion: "2022-03-25", token: process.env.NEXT_PUBLIC_SANITY_API_TOKEN, useCdn: true }); const builder = imageUrlBuilder(client); export const urlFor = (source) => builder.image(source);
问题排查与修复方案
1. 查询结果是数组而非单个对象
Sanity 的 GROQ 查询 *[...] 返回的是数组,哪怕只有一条匹配结果。直接用 project.name 会报错,因为数组没有 name 属性。
修复方式二选一:
// 方案1:从数组中取第一个元素 const project = (await client.fetch(query, { cache: 'force-cache' }))[0]; // 方案2:修改查询语句直接返回单个对象(推荐,更高效) const query = `*[type == "project" && _id == "${params.id}"][0]`; const project = await client.fetch(query, { cache: 'force-cache' });
2. 校验文档 _id 格式
Sanity 草稿文档的 ID 带 drafts. 前缀,正式发布的文档 ID 为纯字符串。如果 params.id 不带前缀,但目标文档是草稿状态,会匹配失败。
可修改查询语句兼容两种情况:
const query = `*[_type == "project" && (_id == "${params.id}" || _id == "drafts.${params.id}")][0]`;
3. 修正 API Token 配置
NEXT_PUBLIC_ 前缀的环境变量会暴露给客户端,如需访问私有数据,改用服务器端环境变量(比如 SANITY_API_TOKEN,去掉 NEXT_PUBLIC_),同时确保 Token 拥有至少 read 权限。
4. 临时禁用缓存测试
force-cache 会缓存空结果,可临时改为 no-store 验证是否是缓存问题:
const project = await client.fetch(query, { cache: 'no-store' });
5. 检查 API 版本与数据集
建议使用较新的 Sanity API 版本(比如 2024-05-01),同时确认 dataset 配置与数据所在数据集一致(比如是否误写为 production,实际数据在 development)。
修复后完整页面示例
import React from 'react' import { client } from '@/lib/sanityClient'; export default async function Page({params}) { // 使用参数化查询,避免注入风险 const query = `*[_type == "project" && _id == $id][0]`; // 参数化传参更安全 const project = await client.fetch(query, { id: params.id }, { cache: 'no-store' }); if (!project) { return <div>项目不存在</div>; } console.log(project); return ( <div> <h1> Dummy static text</h1> <h1>{project.name}</h1> <p>{project.description}</p> </div> ) }
内容的提问来源于stack exchange,提问作者André Gomes
相关产品推荐
相关产品推荐

